Bàn thêm về định nghĩa hàm

Một phần của tài liệu Bai ch dn python bai ch dn python (Trang 29 - 33)

4. Bàn thêm về luồng điều khiển

4.7 Bàn thêm về định nghĩa hàm

Bạn cũng có thể định nghĩa các hàm với số lượng thông số thay đổi. Có ba dạng, và chúng có thể được dùng chung với nhau.

4.7.1 Giá trị thông số mặc định

Dạng hữu dụng nhất là để chỉ định một giá trị mặc định cho một hoặc nhiều thông số. Dạng này tạo một hàm có thể được gọi với ít thông số hơn là nó được định nghĩa để nhận. Ví dụ:

def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):

while True:

ok = raw_input(prompt)

if ok in ('y', 'ye', 'yes'): return True

if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1

if retries < 0: raise IOError, 'refusenik user' print complaint

Hàm này có thể được gọi như sau: ask_ok('Do you really want to quit?') hoặc như sau:

ask_ok('OK to overwrite the file?', 2)của hàm.

Ví dụ này giới thiệu từ khóa in . Nó kiểm tra xem một dãy có chứa một giá trị nào đó không.

Các giá trị mặc định được định giá tại nơi hàm được định nghĩa trong phạm vi định nghĩa (defining scope) , do đó

i = 5

def f(arg=i):

print arg i = 6

f()

sẽ in 5của hàm.

Cảnh báo quan trọng: Giá trị mặc định chỉ được định giá một lần. Điểm này quan trọng khi mặc định là một giá trị khả biến như danh sách, từ điển hoặc các đối tượng của hầu hết mọi lớp. Ví dụ, hàm sau gộp các thông số truyền vào nó từ các lời gọi sau đó:

def f(a, L=[]):

L.append(a) return L print f(1) print f(2) print f(3)

4. Bàn thêm về luồng điều khiển http://www.vithon.org/tutorial/2.5/node6.html

Sẽ in ra [1][1, 2]

[1, 2, 3]

Nếu bạn không muốn mặc định được dùng chung trong các lời gọi sau, bạn có thể viết một hàm như thế này:

def f(a, L=None):

if L is None:

L = []

L.append(a) return L

4.7.2 Thông số từ khóa

Các hàm cũng có thể được gọi theo thông số từ khóa (keyword argument) theo dạng "keyword = value".

Ví dụ, hàm sau:

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):

print "-- This parrot wouldn't", action,

print "if you put", voltage, "volts through it."

print "-- Lovely plumage, the", type print "-- It's", state, "!"

có thể được gọi theo bất kỳ cách nào:

parrot(1000)

parrot(action = 'VOOOOOM', voltage = 1000000)

parrot('a thousand', state = 'pushing up the daisies') parrot('a million', 'bereft of life', 'jump')

nhưng những lời gọi sau đều không hợp lệ:

parrot() # required argument missing

parrot(voltage=5.0, 'dead') # non-keyword argument following keyword parrot(110, voltage=220) # duplicate value for argument

parrot(actor='John Cleese') # unknown keyword

Nói chung, một danh sách thông số phải có bất kỳ thông số vị trí (positional argument) theo sau bởi bất kỳ thông số từ khóa, các từ khóa phải được chọn từ tên thông số chính quy. Các thông số chính quy không nhất thiết phải có giá trị mặc định. Không thông số nào có thể nhận một giá trị nhiều hơn một lần -- tên thông số chính quy tương ứng với thông số vị trí không thể được dùng làm từ khóa trong cùng một lời gọi. Sau đây là một ví dụ sai vì giới hạn này:

>>> def function(a):

... pass

... >>> function(0, a=0)

Traceback (most recent call last):

File "<stdin>", line 1, in ?

TypeError: function() got multiple values for keyword argument 'a'

Khi thông số chính quy cuối có dạng **name , nó nhận một từ điển (dictionary) chứa tất cả các thông số từ khóa trừ những từ khóa tương ứng với thông số chính quy. Điểm này có thể được dùng chung với một thông số chính quy ở dạng *name (bàn đến trong mục con sau) và nhận một bộ (tuple) chứa các thông số vị trí sau danh sách thông số chính quy. (*name bắt buộc phải xuất hiện trước **name.) Ví dụ, nếu ta định nghĩa một hàm như sau:

def cheeseshop(kind, *arguments, **keywords):

print "-- Do you have any", kind, '?'

print "-- I'm sorry, we're all out of", kind for arg in arguments: print arg

print '-'*40

keys = keywords.keys()

4. Bàn thêm về luồng điều khiển http://www.vithon.org/tutorial/2.5/node6.html

keys.sort()

for kw in keys: print kw, ':', keywords[kw]

Nó có thể được gọi như vậy:

cheeseshop('Limburger', "It's very runny, sir.", "It's really very, VERY runny, sir.", client='John Cleese',

shopkeeper='Michael Palin', sketch='Cheese Shop Sketch') và dĩ nhiên nó sẽ in ra:

-- Do you have any Limburger ?

-- I'm sorry, we're all out of Limburger It's very runny, sir.

It's really very, VERY runny, sir.

--- client : John Cleese

shopkeeper : Michael Palin sketch : Cheese Shop Sketch

Lưu ý rằng phương thức sort() của danh sách các tên thông số từ khóa được gọi trước khi in nội dung của từ điển keywords ; nếu điều này không được thực hiện, thứ tự các thông số được in ra không xác định.

4.7.3 Danh sách thông số bất kỳ

Cuối cùng, một lựa chọn ít dùng nhất để chỉ định rằng một hàm có thể được gọi với bất kỳ số thông số.

Các thông số này sẽ được gói và trong một bộ. Trước các thông số không xác định, không hoặc nhiều hơn các thông số chính quy có thể có mặt.

def fprintf(file, format, *args):

file.write(format % args)

4.7.4 Tháo danh sách thông số

Trường hợp ngược xảy ra khi các thông số đã nằm trong một danh sách hoặc một bộ nhưng cần được tháo ra cho lời gọi hàm cần những thông số vị trí riêng. Ví dụ, hàm có sẵn range() cần nhận các thông số riêng start và stop . Nếu chúng không được cung cấp riêng lẻ, viết lệnh gọi hàm với toán tử *để tháo các thông số này ra khỏi một danh sách hoặc bộ:

>>> range(3, 6) # normal call with separate arguments [3, 4, 5]

>>> args = [3, 6]

>>> range(*args) # call with arguments unpacked from a list [3, 4, 5]

Theo cùng một kiểu, từ điển có thể cung cấp các thông số từ khóa với toán tử **:

>>> def parrot(voltage, state='a stiff', action='voom'):

... print "-- This parrot wouldn't", action,

... print "if you put", voltage, "volts through it.", ... print "E's", state, "!"

...>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}

>>> parrot(**d)

-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

4.7.5 Dạng lambda

Theo yêu cầu chung, một vài tính năng thường thấy trong các ngôn ngữ lập trình hàm như Lisp đã được thêm vào Python. Với từ khóa lambda , các hàm vô danh (anonymous function) có thể được tạo ra. Đây là một hàm trả vè tổng của hai thông số: "lambda a, b: a+b". Dạng lambda có thể được dùng ở bất kỳ

4. Bàn thêm về luồng điều khiển http://www.vithon.org/tutorial/2.5/node6.html

nơi nào cần đối tượng hàm. Cú pháp của chúng giới hạn ở một biểu duy nhất. Về ý nghĩa, chúng chỉ là một cách viết gọn của một định nghĩa hàm bình thường. Giống như các định nghĩa hàm lồng nhau, dạng lambda có thể tham chiếu các biến từ phạm vi chứa nó:

>>> def make_incrementor(n):

... return lambda x: x + n ...>>> f = make_incrementor(42)

>>> f(0) 42>>> f(1) 43

4.7.6 Chuỗi tài liệu

Có những quy luật đang hình thành về nội dung và định dạng của các chuỗi tài liệu.

Dòng đầu tiên cần phải luôn luôn là một tóm tắt ngắn, xúc tích về mục đích của đối tượng. Để dễ hiểu, nó không nên chỉ ra cụ thể tên hoặc kiểu của đối tượng vì chúng có thể có ở hình thức khác (từ khi tên là một động từ diễn tả hoạt động của hàm). Dòng này cần bắt đầu bằng một chữ hoa và kết thúc bằng một dấu chấm.

Nếu có nhiều dòng trong chuỗi tài liệu, dòng thứ hai nên là một dòng trống, rõ ràng phân biệt tóm tắt và phần còn lại. Các dòng sau nên là một hoặc nhiều đoạn hướng dẫn về cách gọi, các hiệu ứng phụ, v.v...

Bộ phân tích ngữ pháp Python không lọc thụt hàng từ các chuỗi đa dòng (multi-line string literal) trong Python, so nên các công cụ xử lý tài liệu cần phải lọc thụt hàng nếu cần. Việc này được làm theo một cách chung. Dòng không trống đầu tiên sau dòng đầu tiên của chuỗi xác định mức thụt vào cho toàn bộ chuỗi tài liệu. (Ta không thể dùng dòng đầu tiên vì nó thường nằm kế dấu nháy đầu chuỗi cho nên mức thụt vào của nó không được xác định trong cách viết chuỗi.) Khoảng trắng ``tương đương'' với mức thụt vào này được bò khỏi mỗi đầu dòng trong chuỗi. Không nên có các dòng thụt vào ít hơn, nhưng nếu gặp phải, toàn bộ khoảng trắng đầu của chúng nên được bỏ đi. Tính tương đương của khoảng trắng cần được kiểm tra sau khi mở rộng tab (thông thường thành 8 khoảng trắng).

Đâu là ví dụ của một docstring đa dòng:

>>> def my_function():

... """Do nothing, but document it.

... ... No, really, it doesn't do anything.

... """

... pass

... >>> print my_function.__doc__

Do nothing, but document it.

No, really, it doesn't do anything.

Ghi chú ... đối tượng).4.1

Thật ra, gọi theo tham chiếu đối tượng (call by object reference) có thể là một diễn giải tốt hơn, vì nếu một đối tượng khả đổi được truyền vào, nơi gọi sẽ nhận được các thay đổi do nơi được gọi tạo ra (ví dụ như các phần tử được thêm vào danh sách).

Phiên bản 2.5, tài liệu được cập nhật ngày 19, tháng 09, năm 2006.

Xem Về tài liệu này... về cách đề nghị thay đổi.

4. Bàn thêm về luồng điều khiển http://www.vithon.org/tutorial/2.5/node6.html

Bài chỉ dẫn Python

Một phần của tài liệu Bai ch dn python bai ch dn python (Trang 29 - 33)

Tải bản đầy đủ (PDF)

(122 trang)