Bài 8.2. Python - Truyền tham số

Bài 8.2. Python - Truyền tham số
Vì một định nghĩa hàm có thể có nhiều tham số, một lệnh gọi hàm có thể cần nhiều đối số. Bạn có thể truyền đối số cho các hàm của mình theo nhiều cách. Bạn có thể sử dụng đối số vị trí, cần phải theo thứ tự mà các tham số được viết; đối số từ khóa, trong đó mỗi đối số bao gồm một tên biến và một giá trị; và danh sách và từ điển các giá trị. Hãy xem xét từng cách này lần lượt.
Đối số vị trí
Khi bạn gọi một hàm, Python phải khớp từng đối số trong lệnh gọi hàm với một tham số trong định nghĩa hàm. Cách đơn giản nhất để làm điều này là dựa trên thứ tự của các đối số được cung cấp. Các giá trị được khớp theo cách này được gọi là đối số vị trí.
Để xem cách hoạt động của điều này, hãy xem xét một hàm hiển thị thông tin về thú cưng. Hàm này cho chúng ta biết loại động vật của mỗi thú cưng và tên của thú cưng, như được hiển thị ở đây:
def describe_pet(animal_type, pet_name):
"""Hiển thị thông tin về một thú cưng."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('hamster', 'harry')
Định nghĩa cho thấy rằng hàm này cần một loại động vật và tên của động vật. Khi chúng ta gọi describe_pet()
, chúng ta cần cung cấp một loại động vật và một tên, theo thứ tự đó. Ví dụ, trong lệnh gọi hàm, đối số 'hamster' được gán cho tham số animal_type
và đối số 'harry' được gán cho tham số pet_name
. Trong thân hàm, hai tham số này được sử dụng để hiển thị thông tin về thú cưng đang được mô tả.
Đầu ra mô tả một con chuột hamster tên là Harry:
I have a hamster.
My hamster's name is Harry.
Gọi hàm nhiều lần
Bạn có thể gọi một hàm bao nhiêu lần tùy thích. Mô tả một thú cưng thứ hai, khác yêu cầu chỉ một lệnh gọi hàm describe_pet()
khác:
def describe_pet(animal_type, pet_name):
"""Hiển thị thông tin về một thú cưng."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')
Trong lệnh gọi hàm thứ hai này, chúng ta truyền cho describe_pet()
các đối số 'dog' và 'willie'. Giống như với tập hợp đối số trước đó mà chúng ta đã sử dụng, Python khớp 'dog' với tham số animal_type
và 'willie' với tham số pet_name
. Như trước đây, hàm thực hiện công việc của nó, nhưng lần này nó in ra các giá trị cho một con chó tên là Willie. Bây giờ chúng ta có một con chuột hamster tên là Harry và một con chó tên là Willie:
I have a hamster.
My hamster's name is Harry.
I have a dog.
My dog's name is Willie.
Gọi hàm nhiều lần là một cách làm việc rất hiệu quả. Mã mô tả một thú cưng được viết một lần trong hàm. Sau đó, bất cứ khi nào bạn muốn mô tả một thú cưng mới, bạn gọi hàm với thông tin của thú cưng mới. Ngay cả khi mã để mô tả một thú cưng mở rộng đến 10 dòng, bạn vẫn có thể mô tả một thú cưng mới chỉ trong một dòng bằng cách gọi hàm lại.
Thứ tự quan trọng trong đối số vị trí
Bạn có thể nhận được kết quả không mong muốn nếu bạn trộn lẫn thứ tự của các đối số trong một lệnh gọi hàm khi sử dụng đối số vị trí:
def describe_pet(animal_type, pet_name):
"""Hiển thị thông tin về một thú cưng."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('harry', 'hamster')
Trong lệnh gọi hàm này, chúng ta liệt kê tên trước và loại động vật sau. Vì đối số 'harry' được liệt kê đầu tiên lần này, giá trị đó được gán cho tham số animal_type
. Tương tự, 'hamster' được gán cho pet_name
. Bây giờ chúng ta có một "harry" tên là "Hamster":
I have a harry.
My harry's name is Hamster.
Nếu bạn nhận được kết quả hài hước như thế này, hãy kiểm tra để đảm bảo thứ tự của các đối số trong lệnh gọi hàm của bạn khớp với thứ tự của các tham số trong định nghĩa hàm.
Đối số từ khóa
Một đối số từ khóa là một cặp tên-giá trị mà bạn truyền cho một hàm. Bạn trực tiếp liên kết tên và giá trị trong đối số, vì vậy khi bạn truyền đối số cho hàm, không có sự nhầm lẫn (bạn sẽ không kết thúc với một harry tên là Hamster). Đối số từ khóa giải phóng bạn khỏi việc phải lo lắng về việc sắp xếp đúng thứ tự các đối số trong lệnh gọi hàm, và chúng làm rõ vai trò của mỗi giá trị trong lệnh gọi hàm.
Hãy viết lại describe_pet()
bằng cách sử dụng đối số từ khóa:
def describe_pet(animal_type, pet_name):
"""Hiển thị thông tin về một thú cưng."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(animal_type='hamster', pet_name='harry')
Hàm describe_pet()
không thay đổi. Nhưng khi chúng ta gọi hàm, chúng ta rõ ràng cho Python biết tham số nào mỗi đối số nên được khớp với. Khi Python đọc lệnh gọi hàm, nó biết để gán đối số 'hamster' cho tham số animal_type
và đối số 'harry' cho pet_name
. Đầu ra chính xác cho thấy rằng chúng ta có một con chuột hamster tên là Harry.
Thứ tự của các đối số từ khóa không quan trọng vì Python biết mỗi giá trị nên đi đâu. Hai lệnh gọi hàm sau đây là tương đương:
describe_pet(animal_type='hamster', pet_name='harry')
describe_pet(pet_name='harry', animal_type='hamster')
Giá trị mặc định
Khi viết một hàm, bạn có thể định nghĩa một giá trị mặc định cho mỗi tham số. Nếu một đối số cho một tham số được cung cấp trong lệnh gọi hàm, Python sử dụng giá trị đối số. Nếu không, nó sử dụng giá trị mặc định của tham số. Vì vậy, khi bạn định nghĩa một giá trị mặc định cho một tham số, bạn có thể loại bỏ đối số tương ứng mà bạn thường viết trong lệnh gọi hàm. Sử dụng giá trị mặc định có thể đơn giản hóa các lệnh gọi hàm của bạn và làm rõ cách các hàm của bạn thường được sử dụng.
Ví dụ, nếu bạn nhận thấy rằng hầu hết các lệnh gọi hàm describe_pet()
được sử dụng để mô tả chó, bạn có thể đặt giá trị mặc định của animal_type
là 'dog'. Bây giờ bất kỳ ai gọi describe_pet()
cho một con chó có thể bỏ qua thông tin đó:
def describe_pet(pet_name, animal_type='dog'):
"""Hiển thị thông tin về một thú cưng."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(pet_name='willie')
Chúng ta đã thay đổi định nghĩa của describe_pet()
để bao gồm một giá trị mặc định, 'dog', cho animal_type
. Bây giờ khi hàm được gọi mà không có animal_type
được chỉ định, Python biết sử dụng giá trị 'dog' cho tham số này:
I have a dog.
My dog's name is Willie.
Lưu ý rằng thứ tự của các tham số trong định nghĩa hàm phải được thay đổi. Vì giá trị mặc định làm cho không cần thiết phải chỉ định loại động vật như một đối số, đối số duy nhất còn lại trong lệnh gọi hàm là tên của thú cưng. Python vẫn diễn giải điều này như một đối số vị trí, vì vậy nếu hàm được gọi chỉ với tên của thú cưng, đối số đó sẽ khớp với tham số đầu tiên được liệt kê trong định nghĩa hàm. Đây là lý do tại sao tham số đầu tiên cần phải là pet_name
.
Cách đơn giản nhất để sử dụng hàm này bây giờ là cung cấp chỉ tên của chó trong lệnh gọi hàm:
describe_pet('willie')
Lệnh gọi hàm này sẽ có cùng đầu ra như ví dụ trước. Đối số duy nhất được cung cấp là 'willie', vì vậy nó được khớp với tham số đầu tiên trong định nghĩa, pet_name
. Vì không có đối số nào được cung cấp cho animal_type
, Python sử dụng giá trị mặc định 'dog'.
Để mô tả một động vật khác ngoài chó, bạn có thể sử dụng một lệnh gọi hàm như sau:
describe_pet(pet_name='harry', animal_type='hamster')
Vì một đối số rõ ràng cho animal_type
được cung cấp, Python sẽ bỏ qua giá trị mặc định của tham số này.
Các lệnh gọi hàm tương đương
Vì các đối số vị trí, đối số từ khóa và giá trị mặc định có thể được sử dụng cùng nhau, bạn sẽ thường có nhiều cách tương đương để gọi một hàm. Hãy xem xét định nghĩa sau đây cho describe_pet()
với một giá trị mặc định được cung cấp:
def describe_pet(pet_name, animal_type='dog'):
Với định nghĩa này, một đối số luôn cần được cung cấp cho pet_name
, và giá trị này có thể được cung cấp bằng cách sử dụng định dạng vị trí hoặc từ khóa. Nếu động vật được mô tả không phải là chó, một đối số cho animal_type
phải được bao gồm trong lệnh gọi, và đối số này cũng có thể được chỉ định bằng cách sử dụng định dạng vị trí hoặc từ khóa.
Tất cả các lệnh gọi sau đây sẽ hoạt động cho hàm này:
# Một con chó tên là Willie.
describe_pet('willie')
describe_pet(pet_name='willie')
# Một con chuột hamster tên là Harry.
describe_pet('harry', 'hamster')
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet(animal_type='hamster', pet_name='harry')
Mỗi lệnh gọi hàm này sẽ có cùng đầu ra như các ví dụ trước.
Thực sự không quan trọng bạn sử dụng phong cách gọi nào. Miễn là các lệnh gọi hàm của bạn tạo ra đầu ra mà bạn muốn, chỉ cần sử dụng phong cách mà bạn thấy dễ hiểu nhất.
Tránh lỗi đối số
Khi bạn bắt đầu sử dụng hàm, đừng ngạc nhiên nếu bạn gặp lỗi về đối số không khớp. Đối số không khớp xảy ra khi bạn cung cấp ít hoặc nhiều đối số hơn một hàm cần để thực hiện công việc của nó. Ví dụ, đây là những gì xảy ra nếu chúng ta cố gắng gọi describe_pet()
mà không có đối số nào:
def describe_pet(animal_type, pet_name):
"""Hiển thị thông tin về một thú cưng."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet()
Python nhận ra rằng một số thông tin bị thiếu từ lệnh gọi hàm, và traceback cho chúng ta biết điều đó:
Traceback (most recent call last):
File "pets.py", line 6, in <module>
describe_pet()
TypeError: describe_pet() missing 2 required positional arguments: 'animal_type' and 'pet_name'
Traceback đầu tiên cho chúng ta biết vị trí của vấn đề, cho phép chúng ta nhìn lại và thấy rằng có điều gì đó đã sai trong lệnh gọi hàm của chúng ta. Tiếp theo, lệnh gọi hàm gây lỗi được viết ra để chúng ta thấy. Cuối cùng, traceback cho chúng ta biết lệnh gọi thiếu hai đối số và báo cáo tên của các đối số bị thiếu. Nếu hàm này nằm trong một tệp riêng biệt, chúng ta có thể viết lại lệnh gọi đúng mà không cần mở tệp đó và đọc mã hàm.
Python rất hữu ích khi nó đọc mã của hàm cho chúng ta và cho chúng ta biết tên của các đối số mà chúng ta cần cung cấp. Đây là một động lực khác để đặt tên biến và hàm mô tả. Nếu bạn làm vậy, các thông báo lỗi của Python sẽ hữu ích hơn cho bạn và bất kỳ ai khác có thể sử dụng mã của bạn.
Nếu bạn cung cấp quá nhiều đối số, bạn sẽ nhận được một traceback tương tự có thể giúp bạn khớp đúng lệnh gọi hàm của bạn với định nghĩa hàm.
Comments