Hàm trong Python



Hàm, là một khối code được tổ chức và có thể tái sử dụng, để thực hiện một hành động nào đó. Trong các chương trước, bạn đã làm quen với một số hàm đã được xây dựng sẵn trong Python, điển hình như hàm print(). Tuy nhiên bạn cũng có thể tạo riêng cho mình một hàm với cách định nghĩa và kiểu giá trị cho riêng bạn. Các hàm này được gọi là user-defined function.

Định nghĩa một hàm trong Python

Khi định nghĩa các hàm để cung cấp một tính năng nào đó, bạn cần theo các qui tắc sau:

  • Từ khóa def được sử dụng để bắt đầu phần định nghĩa hàm. Def xác định phần bắt đầu của khối hàm.

  • def được theo sau bởi ten_ham được theo sau bởi các dấu ngoặc đơn ().

  • Các tham số được truyền vào bên trong các dấu ngoặc đơn. Ở cuối là dấu hai chấm.

  • Trước khi viết một code, một độ thụt dòng được cung cấp trước mỗi lệnh. Độ thụt dòng này nên giống nhau cho tất cả các lệnh bên trong hàm đó.

  • Lệnh đầu tiên của hàm là tùy ý, và nó là Documentation String của một hàm đó.

  • Sau đó là lệnh để được thực thi.

Cú pháp

def ten_ham( cac_tham_so ):
   "function_docstring"
   function_suite
   return [bieu_thuc]

Ví dụ

Hàm sau nhận một chuỗi là tham số input và in nó trên màn hình chuẩn:

def printme( str ):
   "Chuoi nay duoc truyen vao trong ham"
   print str
   return

Triệu hồi một hàm trong Python

Để thực thi một hàm, bạn cần gọi hàm đó. Phần định nghĩa hàm cung cấp thông tin về tên hàm các tham số và định nghĩa những hoạt động nào được thực hiện bởi hàm đó. Để thực thi phần định nghĩa của hàm, bạn cần gọi hàm đó. Cú pháp như sau:

ten_ham( cac_tham_so )

Ví dụ sau minh họa cách gọi hàm printme():

 

# Phan dinh nghia ham o day
def printme( str ):
   "Chuoi nay duoc truyen vao trong ham"
   print str
   return;

# Bay gio ban co the goi ham printme
printme("Loi goi dau tien toi custom func!")
printme("Loi goi thu hai toi custom func")

Khi code trên được thực thi sẽ cho kết quả:

Loi goi dau tien toi custom func!
Loi goi thu hai toi custom func

Hàm return() trong Python

Hàm return(bieu_thuc) được sử dụng để gửi điều khiển quay trở lại người gọi với bieu_thuc đã cho. Trong trường hợp không cung cấp bieu_thuc, thì hàm return này sẽ trả về None. Nói cách khác, lệnh return được sử dụng để thoát khỏi định nghĩa hàm.

Các ví dụ trên không trả về bất cứ giá trị nào. Bạn có thể trả về một giá trị từ một hàm như sau:

 

# Phan dinh nghia ham o day
def sum( arg1, arg2 ):
   # Cong hai tham so va tra ve ket qua."
   total = arg1 + arg2
   print "Ben trong ham : ", total
   return total;

# Bay gio ban co the goi ham sum nay
total = sum( 10, 20 );
print "Ben ngoai ham : ", total 

Kết quả là:

Ben trong ham :  30
Ben ngoai ham :  30

Phân biệt argument và parameter trong Python

Có hai kiểu dữ liệu được truyền trong hàm:

  • Kiểu dữ liệu đầu tiên là dữ liệu được truyền trong lời gọi hàm. Dữ liệu này được gọi là argument. Argument có thể là hằng, biến hoặc biểu thức.

  • Kiểu dữ liệu thứ hai là dữ liệu được nhận trong phần định nghĩa hàm. Dữ liệu này được gọi là parameter. Parameter phải là biến để giữ các giá trị đang đến.

Ví dụ:

def addition(x,y):
    		print x+y
x=15
addition(x ,10)
addition(x,x)
y=20
addition(x,y)

Kết quả là:

>>> 
25
30
35
>>>

Với cách phân biệt trên, bạn có thể hiểu hơn về đâu là kiểu tham số bạn đang dùng, còn thực sự thì mình nghĩ nó cũng không quan trọng lắm. Do đó, trong phần tiếp theo, chúng tôi sẽ gọi chung chúng là tham số.

Truyền bởi tham chiếu vs bởi giá trị trong Python

Tất cả parameter (argument) trong Python được truyền bởi tham chiếu. Nghĩa là nếu bạn thay đổi những gì mà một parameter tham chiếu tới bên trong một hàm, thì thay đổi này cũng phản ánh trong hàm đang gọi. Ví dụ:

 

# Phan dinh nghia ham o day
def changeme( mylist ):
   "Thay doi list da truyen cho ham nay"
   mylist.append([1,2,3,4]);
   print "Cac gia tri ben trong ham la: ", mylist
   return

# Bay gio ban co the goi ham changeme function
mylist = [10,20,30];
changeme( mylist );
print "Cac gia tri ben ngoai ham la: ", mylist

Ở đây, chúng ta đang duy trì tham chiếu của đối tượng đang truyền và đang phụ thêm các giá trị trong cùng đối tượng đó. Vì thế đoạn code này sẽ cho kết quả:

Cac gia tri ben trong ham la:  [10, 20, 30, [1, 2, 3, 4]]
Cac gia tri ben ngoai ham la:  [10, 20, 30, [1, 2, 3, 4]]

Bạn theo dõi một ví dụ nữa, tại đây tham số đang được truyền bởi tham chiếu và tham chiếu đang được ghi đè bên trong hàm được gọi.

 

# Phan dinh nghia ham o day
def changeme( mylist ):
   "Thay doi list da truyen cho ham nay"
   mylist = [1,2,3,4]; # Lenh nay gan mot tham chieu moi cho mylist
   print "Cac gia tri ben trong ham la: ", mylist
   return

# Bay gio ban co the goi ham changeme
mylist = [10,20,30];
changeme( mylist );
print "Cac gia tri ben ngoai ham la: ", mylist

Tham số mylist là cục bộ (local) với hàm changeme. Việc thay đổi mylist bên trong hàm này không ảnh hưởng tới mylist. Và cuối cùng code trên sẽ cho kết quả:

Cac gia tri ben trong ham la:  [1, 2, 3, 4]
Cac gia tri ben ngoai ham la:  [10, 20, 30]

Phạm vi biến trong Python

Tất cả các biến trong một chương trình không phải là có thể truy cập tại tất cả vị trí ở trong chương trình đó. Điều này phụ thuộc vào nơi bạn đã khai báo một biến.

Phạm vi biến quyết định nơi nào của chương trình bạn có thể truy cập một định danh cụ thể. Trong Python, có hai khái niệm về phạm vi biến là:

  • Biến toàn cục

  • Biến cục bộ

Biến cục bộ trong Python

Các biến được khai báo bên trong một thân hàm là biến cục bộ. Tức là các biến cục bộ này chỉ có thể được truy cập ở bên trong hàm mà bạn đã khai báo, không thể được truy cập ở bên ngoài thân hàm đó. Ví dụ:

def msg():
    	   a=10
    	   print "Gia tri cua a la",a
    	   return

msg()
print a #no se cho mot error vi bien la cuc bo

Kết quả sẽ cho một lỗi vì biến là cục bộ.

>>> 
Gia tri cua a la 10

Traceback (most recent call last):
  	File "C:/Python27/lam.py", line 7, in >module<
   	 print a #no se cho mot error vi bien la cuc bo
TenError: name 'a' is not defined
>>>

Biến toàn cục trong Python

Biến được định nghĩa bên ngoài hàm được gọi là biến toàn cục. Biến toàn cục có thể được truy cập bởi tất cả các hàm ở khắp nơi trong chương trình. Do đó phạm vi của biến toàn cục là rộng nhất. Ví dụ:

b=20
def msg():
    	   a=10
    	   print "Gia tri cua a la",a
    	   print "Gia tri cua b la",b
           return

           msg()
           print b

Kết quả là:

>>> 
Gia tri cua a la 10
Gia tri cua b la 20
20
>>>

Tham số hàm trong Python

Sau khi đã tìm hiểu về phạm vi biến, tiếp theo chúng ta cùng tìm hiểu về các loại tham số hàm. Python hỗ trợ các kiểu tham số chính thức sau:

  • Tham số bắt buộc

  • Tham số mặc định

  • Tham số từ khóa (tham số được đặt tên)

  • Số tham số thay đổi

Tham số bắt buộc trong Python

Các tham số bắt buộc là các tham số được truyền tới một hàm theo một thứ tự chính xác. Ở đây, số tham số trong lời gọi hàm nên kết nối chính xác với phần định nghĩa hàm.

Bạn theo dõi ví dụ dưới đây:

#Phan dinh nghia cua ham sum 
def sum(a,b):
    		"Ham co hai tham so"
 		 c=a+b
    		  print c

sum(10,20)
sum(20)

Khi code trên được thực thi sẽ cho một lỗi như sau:

>>> 
30

Traceback (most recent call last):
  	File "C:/Python27/su.py", line 8, in >module<
    	sum(20)
TypeError: sum() takes exactly 2 arguments (1 given)
>>>

Giải thích:

1, Trong trường hợp đầu tiên, khi hàm sum() được gọi đã được truyền hai giá trị là 10 và 20, đầu tiên Python so khớp với phần định nghĩa hàm, sau đó 10 và 20 được gán tương ứng cho a và b. Do đó hàm sum được tính toán và được in.

2, Trong trường hợp thứ hai, khi bạn chỉ truyền cho hàm sum() một giá trị là 20, giá trị này được truyền tới phần định nghĩa hàm. Tuy nhiên phần định nghĩa hàm chấp nhận hai tham số trong khi chỉ có một giá trị được truyền, do đó sẽ tạo ra một lỗi như trên.

Tham số mặc định trong Python

Tham số mặc định là tham số mà cung cấp các giá trị mặc định cho các tham số được truyền trong phần định nghĩa hàm, trong trường hợp mà giá trị không được cung cấp trong lời gọi hàm. Ví dụ:

#Phan dinh nghia ham
def msg(Id,Ten,Age=21):
    		"In gia tri da truyen"
    		print Id
   		 print Ten
  		 print Tuoi
   		 return
#Function call
msg(Id=100,Ten='Hoang',Tuoi=20)
msg(Id=101,Ten='Thanh')

Kết quả là:

>>> 
100
Hoang
20
101
Thanh
21
>>>

Giải thích:

1, Trong trường hợp đầu tiên, khi hàm msg() được gọi đang truyền ba giá trị là 100, Hoang, và 20, thì các giá trị này sẽ được gán tương ứng cho các tham số và do đó chúng được in ra tương ứng.

2, Trong trường hợp thứ hai, khi bạn chỉ truyền hai tham số cho hàm msg() được gọi là 101 và Thanh, thì các giá trị này được gán tương ứng cho ID và Ten. Không có giá trị nào được gán cho tham số thứ ba trong lời gọi hàm, và vì thế hàm sẽ lấy giá trị mặc định là 21.

Tham số từ khóa trong Python

Sử dụng tham số từ khóa, tham số được truyền trong lời gọi hàm được kết nối với phần định nghĩa hàm dựa trên tên của tham số. Với trường hợp này, vị trí của các tham số trong lời gọi hàm là tùy ý. Ví dụ:

def msg(id,name):
   		 "In gia tri da truyen"
    		   print id
    		   print ten
 		   return
msg(id=100,ten='Hoang')
msg(ten='Thanh',id=101)

Kết quả là:

>>> 
100
Hoang
101
Thanh
>>>

Giải thích:

1, Trong trường hợp đầu tiên, trong lời gọi hàm msg(), bạn đã truyền hai giá trị và truyền vị trí giống như của chúng trong phần định nghĩa hàm. Sau khi so khớp với phần định nghĩa hàm, thì các giá trị này được truyền tương ứng với các tham số trong phần định nghĩa hàm. Điều này được thực hiện dựa trên tên tham số.

2, Trong trường hợp thứ hai, trong lời gọi hàm msg(), bạn cũng cũng truyền hai giá trị nhưng với vị trí khác với phần định nghĩa hàm. Thì ở đây, dựa vào tên của tham số, các giá trị này cũng được truyền tương ứng cho các tham số trong phần định nghĩa hàm.

Hàm với số tham số thay đổi trong Python

Bạn có thể cần xử lý một hàm mà có số tham nhiều hơn là bạn đã xác định trong khi định nghĩa hàm. Những tham số này được gọi là các tham số có số tham số thay đổi (variable-length args) và không được đặt tên trong định nghĩa hàm, không giống như các tham số bắt buộc và tham số mặc định.

Cú pháp cho một hàm có số thay đổi là:

def tenham([tham_so_chinh_thuc,] *var_args_tuple ):
   "function_docstring"
   function_suite
   return [bieu_thuc]

Một dấu * được đặt trước tên biến để giữ các giá trị của các tham số loại này. Tuple này vẫn là trống nếu không có tham số bổ sung nào được xác định trong khi gọi hàm. Dưới đây là ví dụ đơn giản.

 

# Phan dinh nghia ham o day
def printinfo( arg1, *vartuple ):
   "In mot tham so da truyen"
   print "Ket qua la: "
   print arg1
   for var in vartuple:
      print var
   return;

# Bay gio ban co the goi ham printinfo
printinfo( 10 )
printinfo( 70, 60, 50 )

Kết quả là:

Ket qua la:
10
Ket qua la:
70
60
50

Hàm nặc danh trong Python

Hàm nặc danh (hàm vô danh), hiểu theo cách đơn giản, là hàm không có tên và chúng không được khai báo theo cách chính thức bởi từ khóa def. Để khai báo hàm này, bạn sử dụng từ khóa lambda. Lambda nhận bất kỳ lượng tham số nào và chỉ trả về một giá trị trong dạng một biểu thức đã được ước lượng. Bạn không thể gọi trực tiếp gọi hàm nặc danh để in bởi vì labda cần một biểu thức. Ngoài ra, các hàm lambda có namespace cục bộ của chúng. Dưới đây là cú pháp của hàm lamda:

lambda [arg1 [,arg2,.....argn]]:bieu_thuc

Bạn theo dõi ví dụ sau để hiểu cách hàm lambda làm việc:

#Phan dinh nghia ham
square=lambda x1: x1*x1

#Goi square nhu la mot ham
print "Binh phuong cua so la",square(10)

Kết quả là:

>>> 
Binh phuong cua so la 100
>>>

So sánh hàm chính thức và hàm nặc danh trong Python?

Bạn theo dõi hai ví dụ sau:

Ví dụ cho hàm chính thức:

#Phan dinh nghia ham
def square(x):
    return x*x
	
#Goi ham square
print "Binh phuong cua so la",square(10)

Ví dụ cho hàm nặc danh:

#Phan dinh nghia ham
square=lambda x1: x1*x1

#Goi square nhu la mot ham
print "Binh phuong cua so la",square(10)

Giải thích:

Hàm nặc danh được tạo bởi sử dụng từ khóa lambda, không phải bởi từ khóa def. Hàm này chỉ trả về một giá trị dưới dạng một biểu thức đã được ước lượng.