Trong phần này chúng ta sẽ tìm hiểu về hàm trong Python.
Hàm là một đoạn lệnh trong một chương trình thực hiện một công việc nào đó. Việc dùng hàm có các lợi ích sau:
- Giảm khối lượng mã nguồn
- Dễ quản lý do chương trình được chia thành nhiều phần nhỏ
- Mã nguồn trở nên sáng sủa
- Tái sử dụng lại mã nguồn
- Che giấu thông tin
Trong Python một hàm cũng tương đương với một đối tượng. Giá trị của hàm có thể được gán vào biến, lưu vào trong danh sách hoặc được dùng để làm tham số của các hàm khác… làm cho ngôn ngữ lập trình trở nên tinh xảo hơn.
Có hai loại hàm, thứ nhất là các hàm có sẵn ví dụ như dir(), len(), abs()
… thứ hai là các hàm do chúng ta tạo ra, để tạo ra một hàm (hay còn còn là định nghĩa một hàm) thì chúng ta dùng từ khóa def
.
Định nghĩa một hàm
Chúng ta định nghĩa một hàm bằng từ khóa def
,
phần code bên trong hàm phải thụt lùi vào.
def function(): pass
Sau từ khóa def
là tên hàm với cặp dấu ngoặc tròn ()
và dấu hai chấm. Bên dưới chúng ta thụt lùi vô để viết các đoạn code, phần này là phần thân hàm.
Hàm sau khi được định nghĩa xong sẽ được thực thi khi cần thiết. Trong lập trình thì chúng ta dùng từ “gọi hàm” để chỉ việc sử dụng hàm đó. Chỉ khi chúng ta gọi hàm, đoạn code bên trong thân hàm mới được thực hiện.
myfunc()
Để gọi một hàm thì chỉ đơn giản là ghi lại tên hàm đó cùng với cặp dấu ngoặc tròn ()
.
""" The test.py script shows how to work with functions in Python. author: PhoCode, 2016 """ def showModuleName(): print (__doc__ ) def getModuleFile(): return __file__ a = showModuleName() b = getModuleFile() print (a, b)
Trong ví dụ trên, ở phần đầu chúng ta có một string giới thiệu về đoạn code trong file, đoạn string này có tác dụng giống như lời giới thiệu, mô tả về chương trình vậy. File chứa đoạn code này được gọi là module. Trong đoạn code trên, chúng ta định nghĩa hai hàm, hàm đầu tiên in ra nội dung của biến __doc__,
hàm thứ hai trả về giá trị của biến __file__.
Một hàm có thể có hoặc không có giá trị trả về. Nếu chúng ta không trả về một thứ gì thì mặc định Python sẽ ngầm trả về None
. Hai biến __doc__
và __file__
là hai biến đặc biệt trong Python.
The test.py script shows how to work with functions in Python. author: PhoCode, 2016 None C:\Users\PhoCode\test.py
Như đã nói ở trên, phần thân hàm phải viết lùi vào trong, nếu không sẽ có lỗi.
def f1(): print ("f1()") f1() #f2() def f2(): print ("f2()")
Trong ví dụ trên, chúng ta định nghĩa hai hàm và gọi hai hàm đó. Nhưng một câu lệnh gọi hàm đã bị đánh dấu là chú thích vì nó được gọi trước phần định nghĩa hàm, một hàm luôn luôn phải được định nghĩa trước khi được gọi, tức là phải viết phần định nghĩa trước rồi mới đến câu lệnh gọi.
#f2() def f2(): print ("f2()")
Nếu muốn gọi hàm f2()
thì bạn phải để câu lệnh f2()
sau phần định nghĩa hàm. Nếu không sẽ báo lỗi.
Vị trí của hàm
Một hàm có thể được định nghĩa bên trong một module,
một lớp hoặc bên trong một hàm khác. Hàm được định nghĩa bên trong một lớp được gọi là phương thức.
class Some: @staticmethod def f(): print ("f() method") def f(): print ("f() function") def g(): def f(): print ("f() inner function") f() Some.f() f() g()
Trong ví dụ trên, chúng ta định nghĩa hàm ở những vị trí khác nhau.
class Some: @staticmethod def f(): print ("f() method")
Đoạn code trên định nghĩa một phương thức tĩnh với nhờ vào chỉ thị @staticmethod
trong lớp Some
.
def f(): print ("f() function")
Đoạn code trên định nghĩa một hàm bình thường.
def g(): def f(): print ("f() inner function") f()
Đoạn code trên định nghĩa hàm f()
bên trong hàm g(),
hàm được định nghĩa bên trong một hàm khác được gọi là hàm nội (inner function).
Some.f() f() g()
Chúng ta gọi phương thức tĩnh bằng cách ghi tên lớp, sau đó là dấu chấm và tên phương thức cùng với cặp dấu ngoặc tròn ()
. Các hàm bình thường được gọi bằng cách ghi tên hàm với cặp dấu ngoặc tròn ().
f() method f() function f() inner function
Đối tượng hàm
Bản chất của hàm trong Python là các đối tượng. Chúng được xử lý như các đối tượng tạo ra từ các lớp.
def f(): """This function prints a message """ print ("Today it is a cloudy day") print (isinstance(f, object)) print (id(f)) print (f.__doc__) print (f.__name__)
Đoạn code trên kiểm tra tính đối tượng của hàm.
def f(): """This function prints a message """ print ("Today it is a cloudy day")
Đoạn code trên định nghĩa hàm f()
. Hàm này in một string là màn hình. Ngoài ra hàm này còn có một đoạn string giới thiệu ở đầu nữa.
print (isinstance(f, object))
Hàm isinstance()
có tác dụng kiểm tra xem hàm f()
có phải là một đối tượng của lớp object
hay không. Lớp object là lớp cơ sở, mọi lớp trong Python đều kế thừa từ lớp này.
print (id(f))
Mỗi đối tượng trong Python đều có một id. Hàm
id()
trả về id của đối tượng đó.
print (f.__doc__) print (f.__name__)
Tất cả các đối tượng đều chứa biến bên trong nó, biến trong đối tượng được gọi là các thuộc tính. Hai thuộc tính __doc__
và __name__
là hai thuộc tính có sẵn có các đối tượng trong Python.
True 3077407212 This function prints a message f
Các đối tượng có thể được lưu trữ trong các danh sách hoặc làm tham số cho các hàm khác.
def f(): pass def g(): pass def h(f): print (id(f)) a = (f, g, h) for i in a: print (i) h(f) h(g)
Ở trên chúng ta định nghĩa 3 hàm. Sau đó chúng ta lưu chúng trong một tuple và đưa vào tham số của một hàm.
a = (f, g, h) for i in a: print (i)
Trong đoạn code trên, chúng ta đưa 3 đối tượng vào một tuple và duyệt tuple đó.
h(f) h(g)
Hai dòng trên chúng ta đưa hàm f()
và g()
làm tham số của hàm h().
<function f at 0xb7664fb4> <function g at 0xb766c1b4> <function h at 0xb766c3ac> 3076935604 3076964788
Từ khóa return
Hàm được tạo ra để thực hiện các công việc nào đó. Thường thì các công việc này phải có một kết quả nào đó. Ví dụ bạn viết một hàm làm công việc là tính tổng của một dãy số, sau khi khai báo tên hàm, bạn khai báo biến để lưu giá trị tổng rồi duyệt qua một danh sách cho trước để tính tổng rồi lưu vào biến tổng đó, nhưng khi kết thúc hàm thì biến tính tổng đó bị xóa, bạn chẳng thể nào lấy được biến tổng ở ngoài hàm đó nữa. Lúc này bạn cần dùng đến từ khóa return,
từ khóa return
có tác dụng “trả về” một giá trị của một hàm. Một hàm có thể có hoặc không có từ khóa return,
nếu không có thì Python mặc định ngầm trả về một đối tượng None.
def showMessage(msg): print (msg) def cube(x): return x * x * x x = cube(3) print (x) showMessage("Computation finished.") print (showMessage("Ready."))
Trong đoạn code trên, chúng ta định nghĩa hai hàm. Một hàm có return,
một hàm không.
def showMessage(msg): print (msg)
Hàm showMessage()
không trả về mọt giá trị gì mà chỉ in ra một dòng string.
def cube(x): return x * x * x
Hàm cube()
thực hiện tính lập phương của một số và trả về giá trị của phép tính này.
x = cube(3)
Ở dòng code trên, chúng ta gọi hàm cube()
. Như đã nói ở trên hàm này sẽ trả về một giá trị, chúng ta lưu lại giá trị này bằng cách gán nó cho biến x.
showMessage("Computation finished.")
Ở dòng trên chúng ta gọi hàm showMessage()
có tham số đầu vào là một string. Hàm này chỉ có nhiệm vụ in đoạn string ra màn hình chứ không trả về gì cả.
print (showMessage("Ready."))
Dòng code trên in ra hai lần, vì trong hàm showMessage()
đã có lệnh in ra một string. Hàm này lại được làm đối số trong một hàm print()
khác, mà vì hàm này không có câu lệnh return
nào nên ngầm trả về đối tượng None
nên hàm print()
ở ngoài sẽ in ra None.
Định nghĩa lại hàm
Trong Python bạn có thể định nghĩa lại một hàm đã được định nghĩa sẵn, mặc dù làm thế cũng không có ý nghĩa mấy và thực tế thì trong các ngôn ngữ khác bạn không được phép làm điều này.
from time import gmtime, strftime def showMessage(msg): print (msg) showMessage("Ready.") def showMessage(msg): print (strftime("%H:%M:%S", gmtime()),) print (msg) showMessage("Processing.")
Trong ví dụ trên chúng ta định nghĩa hàm showMessage()
hai lần.
from time import gmtime, strftime
Ở dòng trên chúng ta import
hàm gmtime()
, strftime()
từ module time
.
def showMessage(msg): print (msg )
Đây là hàm showMessage()
được định nghĩa lần thứ nhất.
def showMessage(msg): print (strftime("%H:%M:%S", gmtime()),) print (msg)
Đoạn code trên là phần định nghĩa hàm showMEssage()
lần thứ hai. Lần này chúng ta sử dụng một số hàm lấy thời gian trong module time
.
Ready. 23:49:33 Processing.
Tham số cho hàm
Ví dụ khi bạn cần một hàm làm công việc tính tổng của một dãy số, hàm đó sẽ cần biết phải tính dãy số nào chứ? Và dãy số mà bạn “đưa” cho hàm để nó làm công việc tính toán gọi là tham số. Vậy là bâu giờ bạn biết được quá trình làm việc của một hàm thông thường rồi. Ban đầu hàm nhận vào các tham số, sau đó xử lý chúng và return
lại kết quả cho chúng ta.
def C2F(c): return c * 9/5 + 32 print (C2F(100)) print (C2F(0)) print (C2F(30))
Trong đoạn code trên, chúng ta viết hàm chuyển đổi nhiệt độ từ Celsius sang Fahrenheit. Hàm này nhận vào tham số là nhiệt độ ở Celsius.
212 32 86
Bạn có thể đặt giá trị mặc định cho các tham số, giá trị mặc định sẽ được sử dụng nếu bạn không đưa vào một tham số nào khi gọi hàm.
def power(x, y=2): r = 1 for i in range(y): r = r * x return r print (power(3)) print (power(3, 3)) print (power(5, 5))
Ở trên chúng ta định nghĩa hàm lấy lũy thừa. Hàm này nhận hai tham số, trong đó tham số y
có giá trị mặc định là 2.
9 27 3125
Truyền tham số kiểu tham chiếu
Khi bạn đưa các tham số vào một hàm, bên trong hàm sẽ tạo một biến khác và copy giá trị của tham số truyền vào vào biến mới này, và khi kết thúc hàm thì biến này sẽ bị xóa, tham số kiểu này được gọi là tham trị. Tuy nhiên bạn có thể đưa chính biến ở ngoài vào, hàm sẽ thực hiện xử lý trên biến này luôn chứ không tạo biến mới nữa, tham số kiểu này được gọi là tham chiếu.
def f(x): x = "Bonjour" str = "Hello" print (str) f(str) print(str)
Trong ví dụ trên, chúng ta định nghĩa hàm f(),
hàm này thay đổi giá trị truyền vào thành chuỗi “Bonjour”, tuy nhiên vì là truyền theo kiểu tham trị, nên khi đưa một biến vào hàm này, giá trị của biến đó cũng không thay đổi.
Hello Hello
Mặc định các tham số có kiểu dữ liệu dạng danh sách như list, tuple, dictionary thì các tham số này là tham chiếu.
n = [1, 2, 3, 4, 5] print ("Original list:", n) def f(x): x.pop() x.pop() x.insert(0, 0) print ("Inside f():", x) f(n) print ("After function call:", n)
Trong ví dụ trên, chúng ta truyền vào hàm f()
list n,
sau khi hàm này xử lý xong thì list này cũng thay đổi do hàm này xử lý trên list
n
chứ không tạo list mới.
Original list: [1, 2, 3, 4, 5] Inside f(): [0, 1, 2, 3] After function call: [0, 1, 2, 3]
Biến toàn cục và biến cục bộ
Tiếp theo chúng ta tìm hiểu về biến toàn cục và biến cục bộ.
name = "Jack" def f(): name = "Robert" print ("Within function", name) print ("Outside function", name) f()
Một biến được định nghĩa bên trong một hàm chỉ có thể nhìn thấy bên trong hàm đó và được gọi là biến cục bộ.
Outside function Jack Within function Robert
name = "Jack" def f(): print ("Within function", name) print ("Outside function", name) f()
Các biến được định nghĩa ngoài hàm, nói chính xác hơn là không nằm trong hàm nào thì được gọi là biến toàn cục. Biến này có thể được nhìn thấy ở bất cứ đâu.
Outside function Jack Within function Jack
Tuy nhiên bạn có thể làm cho một biến cục bộ trở thành biến toàn cục bằng từ khóa global
.
name = "Jack" def f(): global name name = "Robert" print ("Within function", name) print ("Outside function", name) f() print ("Outside function", name)
Trong đoạn code trên, chúng ta chỉ định cho biến name
bên trong hàm là biến toàn cục, tức là bay giờ biến name
đó chính là biến name
đã được định nghĩa ở ngoài hàm.
global name name = "Robert"
Ở đoạn code trên, chúng ta dùng từ khóa global
để làm cho một biến cục bộ trở thành biến toàn cục.
Outside function Jack Within function Robert Outside function Robert