Hôm nay chúng ta sẽ cùng nhau đi tìm hiểu về hàm trong Python nhé. Phần này khá là quan trọng, mình mong muốn các bạn thực hành kĩ càng các ví dụ, cũng như làm bài tập để nắm rõ hơn về sử dụng hàm.
1. Hàm
Hàm là một đoạn chương trình được người viết định nghĩa để thực hiện một công việc nào đó mà có thể sử dụng nhiều lần. Trong các ngôn ngữ khác thì hàm khác với thủ tục ở điểm nó trả lại một kết quả. Hàm trong Python có một điểm đặc biệt là nó có thể không trả về một kết quả, bạn có thể coi nó là một thủ tục. Nhưng mình cũng nhắc nhở một điểm, thủ tục trong các ngôn ngữ khác không phải là không trả về giá trị mà nó trả về giá trị là None ( giá trị trống ) và IDE thường bỏ qua nó nên ta có thể coi là nó không trả về giá trị nào.
Từ khóa def khai báo một định nghĩa hàm . Nó phải được theo sau bởi tên hàm, và một danh sách các thông số chính quy trong ngoặc đơn. Các câu lệnh tạo nên thân hàm bắt đầu từ dòng kế tiếp, và bắt buộc phải được thụt vào. Câu lệnh đầu tiên của thân hàm có thể là một chuỗi; chuỗi này là chuỗi tài liệu, hoặc docstringcủa hàm. Các bạn có thể tìm hiểu về docstring ởđây.
Các bạn tham khảo hàm cơ bản mình viết sau:
Việc thực thi một hàm tạo ra một bảng ký hiệu mới dùng cho các biến cục bộ của hàm. Chính xác hơn, mọi phép gán biến trong một hàm chứa giá trị vào bảng ký hiệu cục bộ; và các tham chiếu biến sẽ trước hết tìm trong bảng ký hiệu cục bộ rồi trong bảng ký hiệu toàn cục, và trong bảng các tên có sẵn. Do đó, các biến toàn cục không thể được gán giá trị trực tiếp trong một hàm (trừ khi được đặt trong câu lệnh global ), mặc dù chúng có thể được tham chiếu tới. Để rõ hơn mình xin đưa ra một ví dụ nhỏ:
Thông số thật sự của một lệnh gọi hàm được tạo ra trong bảng ký hiệu cục bộ của hàm được gọi khi nó được gọi; do đó các thông số được truyền theo truyền theo giá trị (call by value) (mà giá trị luôn là một tham chiếu đối tượng, không phải là giá trị của đối tượng).Khi một hàm gọi một hàm khác, một bảng ký hiệu cục bộ được tạo ra cho lệnh gọi đó.
Một định nghĩa hàm tạo tên hàm trong bảng ký hiệu hiện tại. Giá trị của tên hàm có một kiểu được nhận ra bởi trình thông dịch là hàm do người dùng định nghĩa. Giá trị này có thể được gán vào một tên khác và sau đó có thể được sử dụng như một hàm.
Bạn cũng có thể trả lại giá trị cho hàm. Mình sẽ thực hiện đối với hàm fib ở trên nhé:
Để tổng kết lại, chúng ta xem xét ví dụ lớn sau:
Đoạn code ví dụ trên sẽ giúp cho các bạn hiểu cách từ hàm này gọi tới hàm khác. Cũng như kiến thức của các phần trên. Mình mong các bạn cố gắng phân tích kĩ cách thực hiện của ví dụ nhé.
2. Một số cách sử dụng thông số với hàm
Một hàm mặc định khi chúng ta cho nó bao thông số thì khi gọi chúng ta cần bấy nhiêu tham số truyền vào. Điểm đặc biệt trong python là hàm có thể có số thông số nhiều hơn tham số truyền vào, chúng ta cùng đi tham khảo nhé.
2.1 Sử dụng thông số mặc định
Khi chúng ta chỉ định giá trị mặc định cho một hay nhiều thông số, chúng ta có thể gọi hàm với số lượng tham số truyền vào ít hơn số lượng thông số được định nghĩa khi định nghĩa hàm. Ví dụ:
Như trên bạn thấy muốn gọi đến hàm trên cần truyền vào 3 tham số prompt, retries và complaint. Nhưng do tôi đã sử dụng giá trị mặc định cho thông số nên ta có thể gọi đến hàm với ít tham số hơn như: ask_ok('Ban co thuc su muon quit') hay như sau ask_ok('Ban muon ghi vao file?') .
Hôm nay mình viết đến đây, các bạn cố gắng về đọc và thực hành. Bài sau mình sẽ viết tiếp về 1 số cách xử lý thông số của hàm. Sau đây là bài tập của các bạn:
1. Hàm
Hàm là một đoạn chương trình được người viết định nghĩa để thực hiện một công việc nào đó mà có thể sử dụng nhiều lần. Trong các ngôn ngữ khác thì hàm khác với thủ tục ở điểm nó trả lại một kết quả. Hàm trong Python có một điểm đặc biệt là nó có thể không trả về một kết quả, bạn có thể coi nó là một thủ tục. Nhưng mình cũng nhắc nhở một điểm, thủ tục trong các ngôn ngữ khác không phải là không trả về giá trị mà nó trả về giá trị là None ( giá trị trống ) và IDE thường bỏ qua nó nên ta có thể coi là nó không trả về giá trị nào.
Từ khóa def khai báo một định nghĩa hàm . Nó phải được theo sau bởi tên hàm, và một danh sách các thông số chính quy trong ngoặc đơn. Các câu lệnh tạo nên thân hàm bắt đầu từ dòng kế tiếp, và bắt buộc phải được thụt vào. Câu lệnh đầu tiên của thân hàm có thể là một chuỗi; chuỗi này là chuỗi tài liệu, hoặc docstringcủa hàm. Các bạn có thể tìm hiểu về docstring ởđây.
Các bạn tham khảo hàm cơ bản mình viết sau:
Code:
#coding: utf-8 def fib(n): #In mot day cac so Fibonaci cho den n """In mot day cac so Fibonaci cho den n""" a, b = 0, 1 while b < n: print b, a, b = b, a+b # Gọi hàm đã được định nghĩa fib(2000)
Code:
>>> #coding: utf-8 >>> a = 8 >>> def abc(): ... a = 6 ... print a #a cục bộ ... >>> abc() 6 >>> print a 8
Một định nghĩa hàm tạo tên hàm trong bảng ký hiệu hiện tại. Giá trị của tên hàm có một kiểu được nhận ra bởi trình thông dịch là hàm do người dùng định nghĩa. Giá trị này có thể được gán vào một tên khác và sau đó có thể được sử dụng như một hàm.
Bạn cũng có thể trả lại giá trị cho hàm. Mình sẽ thực hiện đối với hàm fib ở trên nhé:
Code:
#coding: utf-8 def fib(n): #In mot day cac so Fibonaci cho den n """In mot day cac so Fibonaci cho den n""" result = [] a, b = 0, 1 while b < n: result.append(b) a, b = b, a+b return result fib100 = fib(100) print fib100
Code:
from sys import exit #Cai nay se duoc gioi thieu sau o phan modul def gold_room(): print "This room is full of gold. How much do you take?" next = raw_input("> ") if "0" in next or "1" in next: how_much = int(next) else: dead("Man, learn to type a number.") if how_much < 50: print "Nice, you're not greedy, you win!" exit(0) else: dead("You greedy bastard!") def bear_room(): print "There is a bear here." print "The bear has a bunch of honey." print "The fat bear is in front of another door." print "How are you going to move the bear?" bear_moved = False while True: next = raw_input("> ") if next == "take honey": dead("The bear looks at you then slaps your face off.") elif next == "taunt bear" and not bear_moved: print "The bear has moved from the door. You can go through it now." bear_moved = True elif next == "taunt bear" and bear_moved: dead("The bear gets pissed off and chews your leg off.") elif next == "open door" and bear_moved: gold_room() else: print "I got no idea what that means." def cthulhu_room(): print "Here you see the great evil Cthulhu." print "He, it, whatever stares at you and you go insane." print "Do you flee for your life or eat your head?" next = raw_input("> ") if "flee" in next: start() elif "head" in next: dead("Well that was tasty!") else: cthulhu_room() def dead(why): print why, "Good job!" exit(0) def start(): print "You are in a dark room." print "There is a door to your right and left." print "Which one do you take?" next = raw_input("> ") if next == "left": bear_room() elif next == "right": cthulhu_room() else: dead("You stumble around the room until you starve.") start()
2. Một số cách sử dụng thông số với hàm
Một hàm mặc định khi chúng ta cho nó bao thông số thì khi gọi chúng ta cần bấy nhiêu tham số truyền vào. Điểm đặc biệt trong python là hàm có thể có số thông số nhiều hơn tham số truyền vào, chúng ta cùng đi tham khảo nhé.
2.1 Sử dụng thông số mặc định
Khi chúng ta chỉ định giá trị mặc định cho một hay nhiều thông số, chúng ta có thể gọi hàm với số lượng tham số truyền vào ít hơn số lượng thông số được định nghĩa khi định nghĩa hàm. Ví dụ:
Code:
def ask_ok(prompt, retries=4, complaint='Xin hay nhap \'dung\' hoac \'sai\''): while True: ok = raw_input(prompt) if ok in ('d','dung): return True if ok in ('s', 'sa', 'sai'): return False retries = retries - 1 if retries < 0: raise IOError, 'refusenik user' print complaint
Hôm nay mình viết đến đây, các bạn cố gắng về đọc và thực hành. Bài sau mình sẽ viết tiếp về 1 số cách xử lý thông số của hàm. Sau đây là bài tập của các bạn:
- Viết 1 hàm thực hiện việc giải phương trình bậc 2: ax^2 + bx + c = 0
- Viết 1 hàm thực hiện việc đổi số nhập vào (thập phân) ra hệ cơ số 2, 8 và 16.
2.2 Thông số từ khóa
Giả sử bạn gọi đến hàm và bạn chỉ muốn giá trị cho 1 số thông số của hàm, bạn phải làm thế nào? Hay sử dụng thông số từ khóa nhé. Nó có dạng "từ khóa = giá trị". Ta xem xét ví dụ sau để biết rõ hơn nhé:
Như trên bạn thấy rằng chúng ta có gọi hàm với các thứ tự tham số truyền vào không đúng với thông số của hàm, chỉ cần truyền theo dạng "từ khóa = giá trị". Ngoài ra bạn có thể truyền giá trị cho thông số mà mình cần.
Đây là một cách sử dụng rất hay của thông số từ khóa. Nhưng 1 số lời gọi sau sẽ bị lỗi:
Chú ý: 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.
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:
Và đây là kết quả:
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.
2.3 Danh sách thông số bất kì:
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ỳ 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
Hôm nay bài học kết thúc tại đây. Các bạn thực hành 1 vài bài tập nho nhỏ để hiểu rõ thêm nhé.
Giả sử bạn gọi đến hàm và bạn chỉ muốn giá trị cho 1 số thông số của hàm, bạn phải làm thế nào? Hay sử dụng thông số từ khóa nhé. Nó có dạng "từ khóa = giá trị". Ta xem xét ví dụ sau để biết rõ hơn nhé:
Code:
#coding: utf-8 def hs(ten_duong, so_nha = 1, tang = 4): print "Bạn đang ở %s số nhà %s tầng %s." % (ten_duong,so_nha,tang) #ta có thể gọi đến hàm trên như sau: hs("Hoàng Diệu") hs("Hoàng Diệu",so_nha = 13) hs(so_nha = 12,ten_duong = "Hoàng Diệu") hs(tang = 1, ten_duong = "Hoàng Diệu")
Đây là một cách sử dụng rất hay của thông số từ khóa. Nhưng 1 số lời gọi sau sẽ bị lỗi:
Code:
hs() # required argument missing hs(ten_duong = "Hoàng Diệu", 4) # non-keyword argument following keyword hs("Hoàng Diệu", ten_duong = "Nguyễn Trãi") # duplicate value for argument hs(ngo = "68/23") # unknown keyword
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:
Code:
#coding: utf-8 def shop(name, *arguments, **keywords): print "Are you want to buy %s? \nYes" % name print "I'm sorry, I have many kinds, what kind you want to buy?" for arg in arguments: print arg keys = keywords.keys() keys.sort() for kw in keys: print kw, ': ', keywords[kw] shop("Storage Drive", "HDD : Hard Disk Drive", "SSD : Solid State Drive", USB = 'Universal Serial Bus', FD = 'Flash Disk')
2.3 Danh sách thông số bất kì:
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ỳ 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
Hôm nay bài học kết thúc tại đây. Các bạn thực hành 1 vài bài tập nho nhỏ để hiểu rõ thêm nhé.
- Sử dụng kiến thức trong bài xây dựng một hàm có tác dụng sau: Tính lương cho phóng viên:Nếu nhập tham số truyền vào có số ngày công và số bài viết thì công thức tính lương = 150000 * số ngày công +5% số bài viết(nếu số bài viết lớn hơn 200) * 5000. Nếu tham số truyền vào có phụ cấp công tác thì cộng thêm 10000 vào lương cơ bản (150000).
- Sử dụng kiến thức trong bài xây dựng hàm đổi từ hệ thập phân ra nhị phân, bát phân, thập lục phân. Nếu chỉ gọi hàm với tham số truyền vào là n thì kết quả trả về là hệ nhị phân. Nếu có thêm hệ cơ số thì trả về hệ cơ số đó.