III. Hàm trong Python
1. Xây dựng hàm:
1. Xây dựng hàm:
Cú pháp một hàm trong Python như sau:
def tên_hàm (tham_biến_1,
tham_biến_2, ...)
# lệnh ...
Trong đó def là từ khóa bắt buộc dùng để khai bó
hàm, tiếp theo là tên hàm được đặt theo qui cách đặt tên, và cuối cùng là danh
sách đối số(nếu có).
Ví dụ:
def binhPhuong(x):
return x*x
Câu lệnh đầu tiên ngay
sau khai báo tên hàm có thể là một chuỗi kí tự tùy ý (string), được
dùng để chỉ dẫn cho hàm (thường gọi là docstring).
Các tham số không cần
xác định kiểu , Python sẽ tự xác định chúng dựa theo giá trị được
truyền khi gọi hàm.
Python không phân biệt
truyền tham biến hay truyền tham trị khi mà bản thân biến cũng không cần
khai báo.
Ví dụ một hàm tính
số Fibonacy
def fib(n):
print 'n =', n
if n > 1:
return n * fib(n − 1)
else:
print 'end of the line'
return 1
hoặc như sau: (
in ra dãy Fibonacci đến một giới hạn tùy ý)
>>> def fib(n): #
write Fibonacci series up to n
...
"""Print a Fibonacci series up to n."""
... a, b = 0, 1
... while b < n:
...
print b,
...
a, b = b, a+b
...
>>> # Now call the function we just
defined:
... fib(2000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
1597
Do không có khai báo rõ
ràng đầu hàm và kết thúc hàm ,chỉ có dấu : nên quy cách viết hàm phải
khá phụthuộc vào cách thụt vào của các lệnh.
Ở đây def fib(n):
là khai báo hàm , nó phải được thụt vào it nhất , các lệnh tiếp theo nằm
bên trong hàm do vậy phải thụt vào nhiều hơn, các lệnh print , if , else ngang
hàng nhau, lệnh return n*fib(n-1) phải thụt vào nhiều hơn if...
Một định nghĩa hàm đưa
tên hàm đó vào một bảng ký hiệu hiện thời. Giá trị của tên hàm là một
kiểu mà được thông dịch như là một hàm người sử dụng định nghĩa. Giá
trị đó có thể được đăng kí một tên khác mà nó cũng có thể sử dụng
như một hàm. Điều này như là một thao tác đổi tên hàm:
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
1 1 2 3 5 8 13 21 34 55 89
Khi hàm không xác định kiểu giá trị trả về
(giống như hàm fib ở trên) nó ngầm định trả về một giá trị gọi là None. Ta có
thể xem giá trị này như sau:
>>> print fib(0)
None
Cũng rất đơn giản để viết một hàm trả về một
danh sách chuỗi Fibonacci thay vì in ra nó:
>>> def fib2(n): # return Fibonacci
series up to n
...
"""Return a list containing the Fibonacci series up to
n."""
... result = []
... a, b = 0, 1
... while b < n:
...
result.append(b) # see below
...
a, b = b, a+b
... return result
...
>>> f100 = fib2(100)
# call it
>>>
f100
# write the result
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
2. Các kĩ thuật mở rộng với hàm:
2.1. Chồng hàm
Do không xác định cụ thể kiểu của các tham số khi khai báo hàm
nên Python không có cách nào phân biệt các hàm chồng tên do vậy nó không hỗ trợ chế chồng
hàm.
2.2. Hàm với tham số có giá trị mặc
định
Python hỗ trợ hàm với tham số có giá trị mặc định , các
tham số có thể truyền theo bất kỳ thứ tự nào nếu chỉra
tên của tham số.
Xét 1 hàm sau
def info(object,
spacing=10, collapse=1):
Khi ấy lời gọi hàm có thể là :
info(odbchelper)
--> object=odbchelper , spacing=10 ,
collapse=1
info(odbchelper, 12)
--> object=odbchelper , spacing=12 ,
collapse=1
info(odbchelper,
collapse=0)
--> object=odbchelper , spacing=10 ,
collapse=0
info(spacing=15, object=odbchelper)
--> object=odbchelper , spacing=15,
collapse =1;
Việc sử dụng tham số có
giá trị mặc định trước giúp thuận tiện khi gọi hàm sẽ có ít tham số cần
truyền hơn định nghĩa cho phép. Xét một ví dụ khác:
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
Có thể gọi hàm này theo các
cách như sau:
ask_ok('Do you really
want to quit?')
hoặc:
ask_ok('OK to overwrite
the file?', 2).
Giá
trị mặc định sẽ được tính tại thời điểm kết thúc định nghĩa hàm trong phạm vi định
nghĩa đó. Vì thế:
i = 5
def f(arg=i):
print arg
i = 6
f()
sẽ in ra giá trị 5 chứ
không phải là 6.
Chú ý quan trọng: Giá trị mặc định chỉ được tính một lần. Điều này
tạo ra một sự chênh lệch khi giá trị mặc định là một đối tượng khả biến như
list, dictionary, hoặc instance của hầu hết các lớp. Ví dụ, hàm dưới đây thực
hiện tích lũy các đối số cho các lời gọi tiếp theo:
def f(a, L=[]):
L.append(a)
return L
print f(1)
print f(2)
print f(3)
Nó sẽ in ra:
[1]
[1, 2]
[1, 2, 3]
Nếu
muốn giá trị mặc định được chia sẻ giữa các lời gọi tiếp sau, thì có thể viết
lại hàm như sau:
def f(a, L=None):
if L is None:
L =
[]
L.append(a)
return L
Các hàm cũng có thể được
gọi sử dụng các đối số từ khóa có dạng “keyword = value”. Ví dụ, hàm sau đây:
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, "!"
hàm này có thể được
gọi với bất kì cách nào như sau:
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
dưới đây lại không có giá trị:
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
Tổng
quát, một danh sách đối số phải có các đối số vị trí bất kì tiếp theo bởi các
đối số từ khóa bất kì, trong đó các từ khóa phải được chọn từ các tên tham số
thông thường. Không quan trọng là tên tham số thông thường có giá trị mặc
định hay không.Không có đối số nào nhận được nhiều hơn một giá trị. Đây là
một ví dụ:
>>> 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'
2.4. Hàm với danh sách đối số tùy ý:
Python cho phép khai báo
2 đối số đặc biệt cho phép tạo ra danh sách các đối số với số lượng
tùy ý. Có nghĩa là mỗi khi gọi hàm đó. Ta có thể xác định bất kì số lượng
đối số nào tùy ý. Ví dụ:
def function(first,second,*remaining):
statement1
statement2
...
Khi
gọi hàm trên, phải cung cấp giá trị cho 2 đối số bắt buộc đầu
tiên.Tuy nhiên với đối số thứ 3, bởi vì nó được đánh dấu với một dấu
* nên bất kì đối số thật sự nào sau 2 đối số đầu tiên sẽ được
cho vào một bộ và gán cho đối số còn lại.
>>> def print_tail(first,*tail):
... print tail
...
>>> print_tail(1,
5, 2, "omega")
(5, 2, 'omega')
Nếu
sử dụng ** trước một đối số thì nó sẽ gắn một từ điển chứa
bất kì đối số từ khóa nòa trong các đối sốtruyền vào mà không phải là
cho đối số bình thường. Ví dụ:
def make_dictionary(max_length
= 10, **entries):
return dict([(key,
entries[key]) for i, key in enumerate(entries.keys()) if i < max_length])
Nếu
gọi hàm này với bất kì đối số từ khóa nào khác max_length, chúng sẽ được
đặt vào trong một từ điển “entries”. Nếu bao gồm cả đối số truyền
cho max_length, nó sẽ được gắn cho đối số thông thường max_length:
>>> make_dictionary(max_length
= 2, key1 = 5, key2 = 7, key3 = 9)
{'key3': 9, 'key2': 7}
Như vậy, các đối số đó
sẽ được nằm trong một bộ. Trước các đối số có số lượng thay đổi, không có
hoặc có vài đối số thông thường có thể xuất hiện. ví dụ:
def fprintf(file,
format, *args):
file.write(format % args)
2.5. Dạng lambda (Hàm inline):
Bên
cạnh việc đăng kí một giá trị trả về cho hàm với một biến, cũng
có thể tạo ra các biến mà chứa các hàm.Python cung cấp từ khóa lambda
để định nghĩa các hàm không được đặt tên có thể đăng kí với các biến. Ta
phải đặt các đối số trước dấu hai chấm, và giá trị trả về đặt
sau từ khóa lambda. Sau khi được đăng kí với một biến.có thể sử dụng
biến này như là một hàm với các đối số và giá trị trả về như ví
dụ sau:
>>> square =
lambda x: x*x
>>> square(3)
9
Cũng
có thể sử dụng các biến khác các thông số trong một lambda. Tuy
nhiên chú ý rằng hàm lambda cũng sửdụng giá trị các biến trong phạm vi nó
được tạo ra.
>>> prefix =
"Note: "
>>> def return_lambda(prefix):
... return lambda
note: prefix + note
...
>>> prefix =
"re: "
>>> f = return_lambda("Attn:
")
>>> f("Carnivorous
octopi")
'Attn: Carnivorous
octopi'
Chú ý rằng tất cả các
hàm trong Python có thể được lưu trữ thành các biến, và thực tế các
biến là đơn giản nhất.
>>> make_note =
return_lambda
>>> make_note("See:
")("lambda calculus")
'See: lambda calculus'
Đây cũng là một dạng hàm
inline như trong một số ngôn ngữ khác
Ví dụ một hàm inline khác:
>>>f=lambda x:x*3
>>>f(2)
6
>>>f(‘Hello’)
‘HelloHelloHello’
Hàm inline chỉ được
phép có 1 câu lệnh , lệnh đó chính là giá trị trả về của
hàm.
Với từ khóa lambda,
các hàm ẩn danh nhỏ có thể được tạo ra. Ví dụở đây là
một hàm mà trả về tổng của 2 đối số của nó: “lambda a, b:
a+b”. Các dạng lambda có thể được sử dụng ở bất cứ nơi
nào đối tượng hàm được yêu cầu. Chúng bị hạn chế bởi một biểu thức
đơn. 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
Hãy like nếu bài viết có ích →
Kết bạn với gisgpsrs trên Facebook
để nhận bài viết mới nóng hổi
Không có nhận xét nào:
Đăng nhận xét