Th4 192020
 

Chúng ta đã giới thiệu sơ qua về khái niệm điều khiển luồng (control follow) trong python. Những phần tiếp theo này chúng ta sẽ đi đến một khái niệm mới trong python đấy là hàm (function) trong python.
Bạn đã quen thuộc với các hàm print (), input () và len () từ các chương trước. Python cung cấp một số hàm dựng sẵn(builtin functions) như thế này, nhưng bạn cũng có thể viết các hàm của riêng mình. Một chức năng giống như một chương trình nhỏ trong một chương trình.
Để hiểu rõ hơn về các hàm trong python, tạo một tập helloFunc.py với nội dung sau.

def hello():
    print('Howdy!')
    print('Howdy!!!')
    print('Hello there.')
hello()
hello()
hello()

Dòng đầu tiên là một câu lệnh def, định nghĩa một hàm có tên hello (). Mã trong khối theo sau câu lệnh def là phần thân của hàm. Mã này được thực thi khi hàm được gọi, không phải khi hàm được xác định lần đầu.
Các dòng hello () sau hàm là các lệnh gọi hàm. Trong mã, một hàm gọi chỉ là tên hàm theo sau là dấu ngoặc đơn, có thể có một số đối số ở giữa dấu ngoặc đơn. Khi thực hiện chương trình đạt được các cuộc gọi này, nó sẽ nhảy đến dòng trên cùng trong hàm và bắt đầu thực thi mã ở đó. Khi đến cuối hàm, thực thi sẽ trở về dòng được gọi là hàm và tiếp tục di chuyển qua mã như trước.
Vì chương trình này gọi hello() ba lần, mã trong hello() chức năng được thực hiện ba lần. Khi bạn chạy chương trình này, đầu ra trông như thế này:

Howdy!
Howdy!!!
Hello there.
Howdy!
Howdy!!!
Hello there.
Howdy!
Howdy!!!
Hello there.

Một mục đích chính của các hàm là nhóm mã được thực thi nhiều lần. Nếu không có chức năng được xác định, bạn sẽ phải sao chép và dán mã này mỗi lần và chương trình sẽ như thế này:

print('Howdy!')
print('Howdy!!!')
print('Hello there.')
print('Howdy!')
print('Howdy!!!')
print('Hello there.')
print('Howdy!')
print('Howdy!!!')
print('Hello there.')

Nói chung, bạn luôn muốn tránh trùng lặp mã bởi vì nếu bạn Bao giờ quyết định cập nhật mã, ví dụ, nếu bạn tìm thấy một lỗi bạn cần sửa lỗi, bạn phải nhớ thay đổi mã ở mọi nơi bạn đã sao chép mã.
Khi bạn có thêm kinh nghiệm lập trình, bạn sẽ thường thấy mã trùng lặp, có nghĩa là loại bỏ mã trùng lặp hoặc sao chép. Sự trùng lặp làm cho chương trình của bạn ngắn hơn, dễ đọc hơn và dễ cập nhật hơn.
Câu lệnh def và các thông số
Khi bạn gọi hàm print () hoặc len (), bạn truyền cho chúng các giá trị, được gọi là đối số, bằng cách nhập chúng giữa các dấu ngoặc đơn. Bạn cũng có thể xác định các hàm riêng của mình chấp nhận đối số. Nhập ví dụ sau vào trình chỉnh sửa tệp và lưu nó dưới dạng helloFunc2.py:

hello(name):
    print('Hello, ' + name)
hello('Alice')
hello('Bob')

Khi bạn chạy chương trình này nó sẽ hiển thị ra màn hình như sau

Hello, Alice
Hello, Bob

Định nghĩa của hàm hello () trong chương trình này có một tham số gọi là name. Các tham số là các biến có chứa các đối số. Khi một hàm được gọi với các đối số, các đối số được lưu trữ trong các tham số. Lần đầu tiên hàm hello() được gọi, nó được truyền đối số ‘Alice’. Việc thực thi chương trình nhập vào hàm và tên tham số được tự động đặt thành ‘Alice’, đây là tên được in bởi câu lệnh print ().
Một điều đặc biệt cần lưu ý về các tham số là giá trị được lưu trữ trong một tham số bị xóa khi hàm trả về. Ví dụ, nếu bạn đã thêm print(name) sau hello(‘Bob’) trong chương trình trước đó, chương trình sẽ cung cấp cho bạn một NameError vì không có tên biến.
Biến này bị hủy sau khi hàm gọi hello (‘Bob’) trả về, vì vậy print (name) sẽ chỉ một biến tên không tồn tại.
Điều này tương tự như cách một biến chương trình bị lãng quên khi chương trình kết thúc. Tôi sẽ nói nhiều hơn về lý do tại sao điều đó xảy ra sau chương này, khi tôi thảo luận về chức năng phạm vi địa phương là gì.
Định nghĩa, gọi, truyền, đối số, thông số(Define, Call, Pass, Argument, Parameter)
Những khái niệm này lúc đầu có thể gây cho bạn một chút rắc rối, chúng ta nhìn vào ví dụ sau

def sayHello(name):
    print('Hello, ' + name)
sayHello('Al')

Để xác định một hàm là tạo ra nó, giống như một câu lệnh gán như spam = 42 tạo biến spam. Câu lệnh def định nghĩa hàm sayHello (). Dòng sayHello (‘Al’) gọi hàm được tạo bây giờ, gửi thực thi đến đầu mã của hàm. Lệnh gọi hàm này còn được gọi là truyền giá trị chuỗi ‘Al’ cho hàm. Một giá trị được truyền cho một hàm trong lệnh gọi hàm là một đối số. Đối số ‘Al’ được gán cho một biến name cục bộ có tên. Các biến có đối số được gán cho chúng là các tham số.
Thật dễ dàng để trộn lẫn các thuật ngữ này, nhưng giữ chúng riêng biệt sẽ đảm bảo rằng bạn biết chính xác văn bản trong chương này có nghĩa gì.
Return giá trị và return biến
Khi bạn gọi hàm len() và truyền cho nó một đối số, chẳng hạn như ‘Xin chào’, lệnh gọi hàm sẽ ước tính giá trị nguyên 5, là độ dài của chuỗi bạn đã truyền. Nói chung, giá trị mà một lệnh gọi hàm ước tính được gọi là giá trị trả về của hàm.
Khi tạo một hàm bằng cách sử dụng câu lệnh def, bạn có thể chỉ định giá trị trả về sẽ là bao nhiêu với câu lệnh return. Một câu lệnh return bao gồm những điều sau đây:

  • Một từ khóa return
  • Một giá trị hoặc biểu thức mà hàm trả về.
    Khi một biểu thức được sử dụng với câu lệnh return, giá trị trả về là những gì biểu thức này đánh giá. Ví dụ, chương trình sau định nghĩa một hàm trả về một chuỗi khác nhau tùy thuộc vào số nào nó được truyền dưới dạng đối số. Nhập mã sau vào trình chỉnh soạn và lưu nó dưới dạng magic8Ball.py:
import random
def getAnswer(answerNumber):
	if answerNumber == 1:
		return 'It is certain'
	elif answerNumber == 2:
		return 'It is decidedly so'
	elif answerNumber == 3:
		return 'Yes'
	elif answerNumber == 4:
		return 'Reply hazy try again'
	elif answerNumber == 5:
		return 'Ask again later'
	elif answerNumber == 6:
		return 'Concentrate and ask again'
	elif answerNumber == 7:
		return 'My reply is no'
	elif answerNumber == 8:
		return 'Outlook not so good'
	elif answerNumber == 9:
		return 'Very doubtful'
r = random.randint(1, 9)
fortune = getAnswer(r)
print(fortune)

Chúng ta có thể rút gọn đoạn mã cuối trong chỉ một dòng

r = random.randint(1, 9)
fortune = getAnswer(r)
print(fortune)

thành
`

print(getAnswer(random.randint(1, 9)))

Giá trị None
Trong Python, có một giá trị gọi là None, đại diện cho sự vắng mặt của một giá trị. Giá trị None là giá trị duy nhất của kiểu dữ liệu noneType. (Các ngôn ngữ lập trình khác có thể gọi giá trị này là null, nil hoặc không xác định.) Giống như các giá trị Boolean True và false, giá trị None nào phải được nhập bằng chữ N.
Giá trị không có giá trị này có thể hữu ích khi bạn cần lưu trữ một cái gì đó đã không thể được nhầm lẫn cho một giá trị thực trong một biến. Một nơi không sử dụng là giá trị trả về của print(). Hàm print() hiển thị văn bản trên màn hình, nhưng nó không cần phải trả lại bất cứ thứ gì theo cùng một cách len() hoặc input(). Nhưng vì tất cả các lệnh gọi hàm cần ước tính thành giá trị trả về, print() trả về None. Để thấy điều này trong thực tế, nhập thông tin sau vào command line:

>>> spam = print('Hello!')
Hello!
>>> None == spam
True

Đằng sau hậu trường, Python thêm return vào cuối bất kỳ định nghĩa hàm nào mà không có câu lệnh return. Điều này tương tự như cách một vòng lặp for hoặc for ngầm kết thúc bằng câu lệnh continue. Ngoài ra, nếu bạn sử dụng câu lệnh return mà không có giá trị (nghĩa là chỉ từ khóa return), thì None được trả về.
Từ khóa đối số và hàm print()
Hầu hết các đối số được xác định bởi vị trí của chúng trong lệnh gọi hàm. Ví dụ: random.randint (1, 10) khác với random.randint (10, 1). Hàm gọi random.randint (1, 10) sẽ trả về một số nguyên ngẫu nhiên trong khoảng từ 1 đến 10 vì đối số thứ nhất là đầu thấp của phạm vi và đối số thứ hai là cao cấp (trong khi random.randint (10, 1) gây ra một lỗi).
Tuy nhiên, thay vì thông qua vị trí của họ, các đối số từ khóa là được xác định bởi từ khóa đặt trước chúng trong lệnh gọi hàm. Đối số từ khóa thường được sử dụng cho các tham số tùy chọn. Ví dụ, hàm print() có các tham số tùy chọn end và sep để chỉ định những gì sẽ được in ở cuối các đối số của nó và giữa các đối số của nó (tách chúng), tương ứng.
Nếu bạn đã chạy một chương trình với mã sau đây:

print('Hello')
print('World')

sẽ hiển thị ra màn hình như thế này

Hello
World

Hai chuỗi xuất ra xuất hiện trên các dòng riêng biệt vì hàm print () tự động thêm một ký tự dòng mới vào cuối chuỗi mà nó được truyền. Tuy nhiên, bạn có thể đặt đối số từ khóa end để thay đổi ký tự dòng mới thành một chuỗi khác. Ví dụ: nếu mã là thế này:

print('Hello', end='')
print('World')

sẽ hiển thị trên màn hình như thế này

HelloWorld

Đầu ra được in trên một dòng vì không còn dòng mới được in sau ‘Hello’. Thay vào đó, chuỗi trống được in. Điều này rất hữu ích nếu bạn cần vô hiệu hóa dòng mới được thêm vào cuối mỗi lệnh gọi hàm print().
Tương tự, khi bạn chuyển nhiều giá trị chuỗi cho print(), hàm sẽ tự động phân tách chúng với một không gian duy nhất. Nhập thông tin sau vào command line:

>>> print('cats', 'dogs', 'mice')
cats dogs mice

Nhưng bạn có thể thay thế chuỗi phân tách mặc định bằng cách chuyển đối số từ khóa sep thành một chuỗi khác. Nhập thông tin sau vào command line:

>>> print('cats', 'dogs', 'mice', sep=',')
cats,dogs,mice

Bạn cũng có thể thêm các đối số từ khóa vào các chức năng bạn viết, nhưng trước tiên, bạn sẽ phải tìm hiểu về danh sách và các loại dữ liệu từ điển trong hai chương tiếp theo. Bây giờ, chỉ cần biết rằng một số hàm có các đối số từ khóa tùy chọn có thể được chỉ định khi hàm được gọi.