Nhiều người dùng Python quen dùng dấu hoa thị cho toán tử nhân và lũy thừa, nhưng trong hướng dẫn này, bạn sẽ khám phá thêm những cách áp dụng khác của dấu hoa thị.
Hầu hết chúng ta dùng dấu hoa thị làm toán tử nhân và lũy thừa, nhưng chúng còn có nhiều cách sử dụng khác khi đóng vai trò toán tử tiền tố trong Python. Sau khi đọc bài viết này, bạn sẽ nắm được toàn bộ cách dùng của dấu hoa thị.
Dấu hoa thị có nhiều trường hợp sử dụng cụ thể trong Python. Nói chung, chúng ta quen với các toán tử nhân và lũy thừa. Nó còn có thể thực hiện một số thao tác khác như mở gói (unpacking), truyền đối số, v.v. trong các tình huống khác nhau. Trước hết, hãy xem cách dùng phổ biến của dấu hoa thị.
Cách dùng chung của * và **
* được dùng làm toán tử nhân, còn ** được dùng làm toán tử lũy thừa.
## declaring variables
a, b =2,3## multiplicationprint("Multiplication of 2 and 3 is {}".format(a * b))## as power operatorprint("2 power 3 is {}".format(a ** b))Được hỗ trợ bởi
Bây giờ bạn đã thấy cách dùng tổng quát và phổ biến nhất của dấu hoa thị. Tuy nhiên vẫn còn những trường hợp sử dụng dấu hoa thị mà có thể bạn chưa biết. Hãy tiếp tục để khám phá những cách dùng ẩn của dấu hoa thị.
1. Unpacking bằng *
Mở gói (unpack) các phần tử từ một list/tuple/set bằng *. Chúng ta sẽ dùng mở gói trong các đoạn mã sau để triển khai một số tính năng khác của dấu hoa thị. Mở gói là ý tưởng cơ bản đằng sau việc dùng dấu hoa thị như toán tử tiền tố.
Giả sử chúng ta muốn gán phần tử đầu tiên của list/tuple/set cho a và các phần tử còn lại cho b. Thông thường, chúng ta sẽ làm điều này bằng cách cắt (slicing).
## general approach
nums =[i for i inrange(1,6)]
a = nums[0]
b = nums[1:]print(a, b)print("--------------------------")## hard approach
squares =[i **2for i inrange(1,6)]
a = squares[0]
b =[]for i inrange(1,len(squares)):
b.append(squares[i])print(a, b)Được hỗ trợ bởi
1[2,3,4,5]--------------------------1[4,9,16,25]Được hỗ trợ bởi
Bây giờ, chúng ta sẽ dùng toán tử * để thực hiện việc này trong một dòng mã.
nums =[i for i inrange(1,6)]## a sẽ là 1 và b sẽ là một list chứa các phần tử còn lại
a,*b = nums
print(a, b)Được hỗ trợ bởi
Ở đây a có kiểu giống phần tử lấy ra từ list và b là một list. Mở gói cũng hoạt động trên tuple và set giống như với list. Hãy xem vài ví dụ.
## using tuple## here first element will assign to a and last element to c
a,*b, c =(1,2,3,4,5)print(a, b, c)print("--------------------------")## using sets
a,*b, c ={1,4,9,16,25}print(a, b, c)Được hỗ trợ bởi
1[2,3,4]5--------------------------1[4,9,16]25Được hỗ trợ bởi
1.1. Kết hợp các iterable khác nhau
Chúng ta có thể thêm hai iterable khác nhau vào list/set/tuple bằng mở gói. Thông thường, ta phải chuyển đổi các iterable và kết hợp chúng thành một. Tuy nhiên không cần thiết nếu dùng *. Hãy xem ví dụ.
## combining a tuple, list, set
nums =[1,2,3]
nums2 =(4,5,6)
nums3 ={7,8,9}## we convert the combined elements into any iterable we want## here i am converting into a list
_list =[*nums,*nums2,*nums3]
_tuple =(*nums,*nums2,*nums3)
_set ={*nums,*nums2,*nums3}print(type(_list))print(_list)print("------------------------")print(type(_tuple))print(_tuple)print("------------------------")print(type(_set))print(_set)Được hỗ trợ bởi
<class'list'>[1,2,3,4,5,6,8,9,7]------------------------<class'tuple'>(1,2,3,4,5,6,8,9,7)------------------------<class'set'>{1,2,3,4,5,6,7,8,9}Được hỗ trợ bởi
1.2. Mở gói lồng nhau
Mở gói lồng nhau là lấy ra các phần tử từ cấp đầu tiên của các mục đã trích xuất. Xem ví dụ để hình dung rõ hơn ý tôi muốn nói.
languages =["Python","HTML","CSS","JS"]## unpacking[[first_letter,*remaining],*other]= languages
print(first_letter, remaining, other)Được hỗ trợ bởi
Như đã thấy, ** được dùng để mở gói các phần tử từ một dictionary. Ta phải biết các khóa của dictionary để trích xuất giá trị khi mở gói. Hãy xem ví dụ.
## sample dictionary
person ={"name":"John","age":19,"year_of_passing":"2021"}
string ="Name:-{name} Year Of Graduation:-{year_of_passing} Age:-{age}".format(**person)print(string)Được hỗ trợ bởi
Không phổ biến lắm khi dùng ** để trích xuất các phần tử từ một dictionary.
3. Dấu hoa thị trong hàm
Chúng ta có thể truyền và thu nhận đối số bằng dấu hoa thị trong hàm để giảm số dòng mã.
3.1. Unpacking trong hàm
Toán tử * được dùng để gọi hàm bằng cách mở gói một iterable. Giả sử ta có một list và cần truyền từng phần tử của nó riêng lẻ vào print(). Bạn sẽ làm gì? Có lẽ bạn đang nghĩ đến một vòng lặp. Nhưng * giúp việc này trở nên rất dễ.
Chỉ cần truyền iterable dưới dạng *tên_iterable. Nó sẽ mở gói iterable và truyền từng phần tử một cách riêng rẽ.
nums =[i for i inrange(1,6)]## passsing list using the *print(*nums)Được hỗ trợ bởi
Chúng ta đã thấy cách thu nhận nhiều phần tử vào một list bằng *. Giờ hãy học cách thu nhận nhiều cặp khóa-giá trị bằng **.
def_object(name,**properties):print(name, properties)
_object("Car", color="Red", cost=999999, company="Ferrari")Được hỗ trợ bởi
Car {'ceo':'Louis','color':'Red','cost':999999,'company':'Ferrari'}Được hỗ trợ bởi
4. Đối số chỉ-từ-khóa cùng với đối số vị trí
Đối số có tên được gọi là đối số từ khóa (keyword argument). Các đối số khác được gọi là đối số vị trí (positional argument). Trước hết, bạn cần hiểu sự khác nhau giữa đối số từ khóa và vị trí. Hãy xem ví dụ.
## name is a positional argument## color and cost are keyword argumentsdefsample(car, color =None, cost =None):print("Car:-{} Color:-{}, Cost:-{}".format(car, color, cost))Được hỗ trợ bởi
Ta có thể dùng tên tham số để truyền đối số khi gọi hàm cho các đối số từ khóa. Nếu không truyền gì cho đối số từ khóa, chúng sẽ nhận giá trị mặc định được cung cấp trong định nghĩa hàm.
Ta có thể chỉ định đối số từ khóa bằng từ khóa hoặc vị trí của đối số.
Bây giờ bạn đã hiểu về đối số vị trí và từ khóa. Hãy đi vào chủ đề chính.
Đối số chỉ-từ-khóa chỉ được chỉ định bằng từ khóa. Ta không thể đặt chúng theo vị trí như trước. Ta phải khai báo các đối số từ khóa sau đối số * để thu nhận chỉ-từ-khóa.
defkeyword_only(*items, _list, default =False):print(items)print(_list)print(default)Được hỗ trợ bởi
Chúng ta phải dùng các từ khóa_list và default khi gọi hàm vì chúng đứng sau *items. Nếu không dùng từ khóa để gọi, ta sẽ gặp lỗi. Hãy xem cả hai trường hợp.
nums =[i **2for i inrange(1,6)]## calling the function
keyword_only(1,2,3,4,5, _list = nums, default =True)Được hỗ trợ bởi
Chúng ta nhận lỗi cho biết thiếu một đối số bắt buộc kiểu chỉ-từ-khóa. Vì vậy, ta phải dùng từ khóa khi gọi các đối số chỉ-từ-khóa. Đối số chỉ-từ-khóa chỉ được định nghĩa sau đối số * trong hàm.
5. Đối số chỉ-từ-khóa không kèm đối số vị trí
Nếu muốn chỉ chấp nhận các đối số chỉ-từ-khóa mà không có đối số vị trí, Python cho phép dùng * trong tham số hàm để đạt được điều này. Hãy xem ví dụ.
Hàm trên chỉ nhận các đối số chỉ-từ-khóa. Chúng ta phải truyền đối số kèm theo từ khóa. Nếu không, sẽ gặp lỗi. * trong định nghĩa hàm nhằm đảm bảo hàm chỉ nhận đối số thông qua từ khóa. Bất kỳ tham số nào được định nghĩa sau tham số * trong hàm đều phải được chỉ định bằng từ khóa khi gọi hàm.
## calling the function using keyword 'name'
_sample(name ="Datacamp")Được hỗ trợ bởi
## calling the function without using keyword 'name'## we will get a TypeError
_sample("Datacamp")Được hỗ trợ bởi
---------------------------------------------------------------------------
TypeError Traceback(most recent call last)<ipython-input-12-fe0d3718b56c>in<module>()1 ## calling the function without using keyword 'name'2 ## we will get a TypeError
---->3samp("Datacamp")TypeError:samp() takes 0 positional arguments but 1 was given
Được hỗ trợ bởi
Rõ ràng hàm _sample() chỉ nhận các đối số chỉ-từ-khóa*.
Kết luận
Nhà phát triển bổ sung tính năng mới trong mỗi phiên bản Python. Dấu hoa thị là đặc biệt và giúp rút gọn một số phần của mã. Ta không thể chấp nhận nhiều đối số vị trí nếu không có *, và các đối số chỉ-từ-khóa cũng cần * để triển khai tính năng đó. Các thao tác khác của dấu hoa thị có thể đạt được bằng nhiều dòng mã. Hãy luyện tập để hiểu rõ hoàn toàn. Cảm ơn bạn đã đọc!
Hầu hết chúng ta dùng dấu hoa thị làm toán tử nhân và lũy thừa, nhưng chúng còn có nhiều cách sử dụng khác khi đóng vai trò toán tử tiền tố trong Python. Sau khi đọc bài viết này, bạn sẽ nắm được toàn bộ cách dùng của dấu hoa thị.
Dấu hoa thị có nhiều trường hợp sử dụng cụ thể trong Python. Nói chung, chúng ta quen với các toán tử nhân và lũy thừa. Nó còn có thể thực hiện một số thao tác khác như mở gói (unpacking), truyền đối số, v.v. trong các tình huống khác nhau. Trước hết, hãy xem cách dùng phổ biến của dấu hoa thị.
Cách dùng chung của * và **
* được dùng làm toán tử nhân, còn ** được dùng làm toán tử lũy thừa.
Bây giờ bạn đã thấy cách dùng tổng quát và phổ biến nhất của dấu hoa thị. Tuy nhiên vẫn còn những trường hợp sử dụng dấu hoa thị mà có thể bạn chưa biết. Hãy tiếp tục để khám phá những cách dùng ẩn của dấu hoa thị.
1. Unpacking bằng *
Mở gói (unpack) các phần tử từ một list/tuple/set bằng *. Chúng ta sẽ dùng mở gói trong các đoạn mã sau để triển khai một số tính năng khác của dấu hoa thị. Mở gói là ý tưởng cơ bản đằng sau việc dùng dấu hoa thị như toán tử tiền tố.
Giả sử chúng ta muốn gán phần tử đầu tiên của list/tuple/set cho a và các phần tử còn lại cho b. Thông thường, chúng ta sẽ làm điều này bằng cách cắt (slicing).
Bây giờ, chúng ta sẽ dùng toán tử * để thực hiện việc này trong một dòng mã.
Ở đây a có kiểu giống phần tử lấy ra từ list và b là một list. Mở gói cũng hoạt động trên tuple và set giống như với list. Hãy xem vài ví dụ.
1.1. Kết hợp các iterable khác nhau
Chúng ta có thể thêm hai iterable khác nhau vào list/set/tuple bằng mở gói. Thông thường, ta phải chuyển đổi các iterable và kết hợp chúng thành một. Tuy nhiên không cần thiết nếu dùng *. Hãy xem ví dụ.
1.2. Mở gói lồng nhau
Mở gói lồng nhau là lấy ra các phần tử từ cấp đầu tiên của các mục đã trích xuất. Xem ví dụ để hình dung rõ hơn ý tôi muốn nói.
2. Unpacking bằng **
Như đã thấy, ** được dùng để mở gói các phần tử từ một dictionary. Ta phải biết các khóa của dictionary để trích xuất giá trị khi mở gói. Hãy xem ví dụ.
Không phổ biến lắm khi dùng ** để trích xuất các phần tử từ một dictionary.
3. Dấu hoa thị trong hàm
Chúng ta có thể truyền và thu nhận đối số bằng dấu hoa thị trong hàm để giảm số dòng mã.
3.1. Unpacking trong hàm
Toán tử * được dùng để gọi hàm bằng cách mở gói một iterable. Giả sử ta có một list và cần truyền từng phần tử của nó riêng lẻ vào print(). Bạn sẽ làm gì? Có lẽ bạn đang nghĩ đến một vòng lặp. Nhưng * giúp việc này trở nên rất dễ.
Chỉ cần truyền iterable dưới dạng *tên_iterable. Nó sẽ mở gói iterable và truyền từng phần tử một cách riêng rẽ.
3.2. Đóng gói phần tử
Đóng gói nghĩa là thu nhận nhiều phần tử cùng lúc. Chúng ta dùng tính năng này trong lời gọi hàm.
Bây giờ, ta có thể truyền bất kỳ số lượng số nguyên nào để tính trung bình. Hàm average thu nhận tất cả đối số như một list.
Chúng ta đã thấy cách thu nhận nhiều phần tử vào một list bằng *. Giờ hãy học cách thu nhận nhiều cặp khóa-giá trị bằng **.
4. Đối số chỉ-từ-khóa cùng với đối số vị trí
Đối số có tên được gọi là đối số từ khóa (keyword argument). Các đối số khác được gọi là đối số vị trí (positional argument). Trước hết, bạn cần hiểu sự khác nhau giữa đối số từ khóa và vị trí. Hãy xem ví dụ.
Ta có thể dùng tên tham số để truyền đối số khi gọi hàm cho các đối số từ khóa. Nếu không truyền gì cho đối số từ khóa, chúng sẽ nhận giá trị mặc định được cung cấp trong định nghĩa hàm.
Ta có thể chỉ định đối số từ khóa bằng từ khóa hoặc vị trí của đối số.
Thứ tự của các đối số từ khóa không quan trọng nếu ta gọi chúng bằng tên đã định nghĩa trong hàm.
Bây giờ bạn đã hiểu về đối số vị trí và từ khóa. Hãy đi vào chủ đề chính.
Đối số chỉ-từ-khóa chỉ được chỉ định bằng từ khóa. Ta không thể đặt chúng theo vị trí như trước. Ta phải khai báo các đối số từ khóa sau đối số * để thu nhận chỉ-từ-khóa.
Chúng ta phải dùng các từ khóa _list và default khi gọi hàm vì chúng đứng sau *items. Nếu không dùng từ khóa để gọi, ta sẽ gặp lỗi. Hãy xem cả hai trường hợp.
Điều gì xảy ra nếu ta gọi hàm keyword_only bằng các đối số vị trí.
Chúng ta nhận lỗi cho biết thiếu một đối số bắt buộc kiểu chỉ-từ-khóa. Vì vậy, ta phải dùng từ khóa khi gọi các đối số chỉ-từ-khóa. Đối số chỉ-từ-khóa chỉ được định nghĩa sau đối số * trong hàm.
5. Đối số chỉ-từ-khóa không kèm đối số vị trí
Nếu muốn chỉ chấp nhận các đối số chỉ-từ-khóa mà không có đối số vị trí, Python cho phép dùng * trong tham số hàm để đạt được điều này. Hãy xem ví dụ.
Hàm trên chỉ nhận các đối số chỉ-từ-khóa. Chúng ta phải truyền đối số kèm theo từ khóa. Nếu không, sẽ gặp lỗi. * trong định nghĩa hàm nhằm đảm bảo hàm chỉ nhận đối số thông qua từ khóa. Bất kỳ tham số nào được định nghĩa sau tham số * trong hàm đều phải được chỉ định bằng từ khóa khi gọi hàm.
Rõ ràng hàm _sample() chỉ nhận các đối số chỉ-từ-khóa*.
Kết luận
Nhà phát triển bổ sung tính năng mới trong mỗi phiên bản Python. Dấu hoa thị là đặc biệt và giúp rút gọn một số phần của mã. Ta không thể chấp nhận nhiều đối số vị trí nếu không có *, và các đối số chỉ-từ-khóa cũng cần * để triển khai tính năng đó. Các thao tác khác của dấu hoa thị có thể đạt được bằng nhiều dòng mã. Hãy luyện tập để hiểu rõ hoàn toàn. Cảm ơn bạn đã đọc!
Nếu bạn muốn tìm hiểu thêm về Python, hãy học khóa Python Data Science Toolbox (Phần 1) của DataCamp.
Chúc bạn viết code vui vẻ :)