Ở phần trước chúng ta đã cũng nhau tìm hiểu về kiểu dữ liệu set, generators, else và hai cặp từ khóa là if __name__ == "__main__" và with ... as .... Mình hy vọng nó những thứ đó sẽ giúp ích phần nào đó trong quá trình tìm hiểu về Python của mọi người. Hôm nay, chúng ta lại tiếp tục tìm hiểu thêm về chính ngôn ngữ lập trình này nhé

Decorator(Hàm lồng hàm)
Có thể, bởi vì mọi người đã quen với hàm là một chương trình con thực hiện một việc nào đó giông như các ngôn ngữ lập trình khác nên mọi người đôi khi không để ý rằng trong Python, hàm cũng là một đối tượng. Chúng hoàn toàn có thể tạo ra các hàm(phương thức) mới. Vậy tại sao chúng ta lại cần tới nó? Chúng có thể được sử dụng cho nhiều việc khác nhau giống như là bạn viết một hàm là đo đạt thời gian thực hiện của một hàm nào đó thay vì copy hàm đấy rồi phải mất công sửa lại bạn có thể dễ ràng thay nó bằng một hàm khác,…
| import time | |
| def meansureExecute(func): | |
| print("Meansure excution time of %s in 1,000,000 times." % func.__name__) | |
| def calculate(*args, **kargs): | |
| start = time.perf_counter() | |
| for i in range(1000000): | |
| func(*args, **kargs) | |
| end = time.perf_counter() | |
| return (end - start) | |
| return calculate | |
| def getPrimeNumbers(n): | |
| isPrime = [True for i in range(n + 1)] | |
| isPrime[0], isPrime[1] = False, False | |
| for i in range(2, n + 1): | |
| if(isPrime[i]): | |
| for j in range(i * i, n + 1, i): | |
| isPrime[j] = False | |
| primeNums = [] | |
| for i in range(n + 1): | |
| if(isPrime[i]): | |
| primeNums.append(i) | |
| return primeNums | |
| meansure = meansureExecute(getPrimeNumbers) | |
| print("Average time = %fs" % (meansure(100) / 1000000)) | |
| #OUTPUT: | |
| #Meansure excution time of getPrimeNumbers in 1,000,000 times. | |
| #Average time = 0.000021s | |
| #Your computer may get a different result |
Một số decorator hữu dụng
Như ở phần trên, mình đã giải thích về decorators. Tiếp theo đây, mình sẽ giới thiệu cho mọi người một số decorator khá hữu dụng trong khi coding.
Đầu tiện mình sẽ giới thiệu về @property. Nó cho phép chúng ta tùy biến cách truy cập thới một thuộc tính nào đó trong đối tượng và một trong những cách sử dụng phổ biến của nó là việc “trở thành” getter giống như các ngôn ngữ lập trình khác
| class Order(object): | |
| def __init__(self, dictOders): | |
| self._dictOrders = dictOders | |
| @property | |
| def has_cheese(self): | |
| return (True if 'cheese' in self._dictOrders.keys() else False) | |
| firstOrders = { | |
| "cheese" : 4, | |
| "apple" : 8, | |
| "pie" : 5 | |
| } | |
| secondOrder = { | |
| "salad" : 9, | |
| "tomato" : 3, | |
| "noodle" : 8 | |
| } | |
| fstOrd = Order(firstOrders) | |
| sndOrd = Order(secondOrder) | |
| if(fstOrd.has_cheese): | |
| print("This order has cheese.") | |
| if(not sndOrd.has_cheese): | |
| sndOrd.has_cheese = True | |
| #OUTPUT: | |
| #This order has cheese. | |
| #Traceback (most recent call last): | |
| # File ".\property_example.py", line 28, in <module> | |
| # sndOrd.has_cheese = True | |
| #AttributeError: can't set attribute | |
| #because we can't change the value of has_cheese, the only thing we can do with it is get a value |
Tiếp theo ta sẽ nói đến <fuction_name>.setter. Decorator này thường được dùng trong class và nó giống như là setter trong các ngôn ngữ khác
| class Order(object): | |
| def __init__(self, dictOders): | |
| self._dictOrders = dictOders | |
| @property | |
| def cheese(self): | |
| if('cheese' not in self._dictOrders.keys()): | |
| return 0 | |
| return self._dictOrders['cheese'] | |
| @cheese.setter | |
| def cheese(self, value): | |
| self._dictOrders['cheese'] = value | |
| orderList = { | |
| "salad" : 9, | |
| "tomato" : 3, | |
| "noodle" : 8 | |
| } | |
| order = Order(orderList) | |
| print("This order has %d cheese." %(order.cheese)) | |
| order.cheese = 5 | |
| print("Now it has %d." %(order.cheese)) | |
| #OUTPUT: | |
| #This order has 0 cheese. | |
| #Now it has 5. |
Ngoài ra, còn có nhiều decorator khác nữa cũng rất thú vị và mình sẽ đề cập ở một bài viết khác nhé.
__new__ và __init__
Mọi người đều đã quen với method __init__, nó có thể được coi như là constructor của class trong Python. Tuy nhiên, có lẽ không nhiều người biết rằng trước khi method __init__, Python sẽ chạy một method khác đó chính là __new__ và sau đó đối tượng mà bạn muốn sẽ được tạo ra và method __init__ mới bắt đầu thực hiện.
| class A(object): | |
| _dict = dict() | |
| def __new__(cls): | |
| if 'key' in A._dict: | |
| print("EXISTS") | |
| return A._dict['key'] | |
| else: | |
| print("NEW") | |
| return super(A, cls).__new__(cls) | |
| def __init__(self): | |
| print("INIT") | |
| A._dict['key'] = self | |
| print("") | |
| a1 = A() | |
| a2 = A() | |
| a3 = A() | |
| #OUTPUT: | |
| #NEW | |
| #INIT | |
| #EXISTS | |
| #INIT | |
| #EXISTS | |
| #INIT | |
| # | |
| #source: https://stackoverflow.com/questions/674304/why-is-init-always-called-after-new |
Lambda và những hàm liên quan
Trước khi tìm hiểu về lambda, ta cần biết đến một khái niệm đó chính là lập trình hàm(functional programming). Lập trình hàm là một phong cách của ngôn ngữ lập trình lấy nền tảng từ hàm toán học với khả năng không thay đổi trạng thái của chúng. Vậy chúng có đặc điểm gì mà khiến ta phải tạo ra một loại gọi là lập trình hàm? Chúng ta thấy rằng, một hàm toán học với một tham số nhất định chúng chỉ có thể ánh xạ tới một giá trị nhất định, không bao giờ có thể ánh xạ tới một giá trị khác. Chính vì đặc điểm đó đã kiến việc lập trình hàm trở nên dễ ràng trong việc test, hiệu quả và dễ dành chạy song song hơn.
Vậy lambda là gì? hiểu đơn giản là từ khóa lambda giúp ta tạo ra một hàm theo kiểu lập trình hàm với một cách ngắn gọn hơn nhiều và bởi vì lambda cũng là một hàm nên chúng hoàn toàn có thể được gán cho một biến hay được sử dụng như các hàm thông thường.
| square = lambda x : x * x | |
| print("%d" %(square(8))) | |
| #OUTPUT: | |
| #64 |
Vậy có những hàm nào mà ta thường sử dụng với lambda? Chúng ta có thể sử dụng lambda trong rất nhiều hàm khác nhau. Tuy nhiên hôm nay mình sẽ giới thiệu tới mọi người 2 hàm đó là map() và filter().
Trước tiên, chúng ta sẽ nói về map() trước nhé. map() là một hàm generator(còn nó là gì mình đã giải thích ở phần 1) là các giá trị mà hàm đã cho ứng với mỗi một phần tử của mỗi một tham số. Trong một số trường hợp việc sử dụng lambda sẽ giúp code của bạn trở nên gọn gàng và dễ đọc hơn rất nhiều.
| square = lambda x : x * x | |
| xValues = [x for x in range(20)] | |
| print("%r" % xValues) | |
| for y in map(square, xValues): | |
| print("%d" % y, end="\t") | |
| #OUTPUT: | |
| #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] | |
| #0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 |
Tiếp đên là hàm filter(). Cũng tương tự hàm map() là một hàm generator tuy nhiên các giá trị của nó là các giá trị kiến cho hàm ứng với nó trả về giá trị True
| isEven = lambda x : x % 2 == 0 | |
| xValues = [x for x in range(20)] | |
| print("%r" % xValues) | |
| for y in filter(isEven, xValues): | |
| print("%d" % y, end="\t") | |
| #OUTPUT: | |
| #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] | |
| #0 2 4 6 8 10 12 14 16 18 |
The Zen of Python
Cuối cùng, chúng ta sẽ nhắc đến một danh sách các quy tắc trong Python giúp cho việc hiểu và sử dụng nó được hiệu quả hơn. Bạn hoàn toàn có thể đọc phiên bản tiếng anh của nó bằng cách ở python và import this rồi chạy nó. Tuy nhiên, bài viết này mình sẽ để bản dịch trên Wikipedia ở dưới(Link ở đây)

Xinh đẹp thì tốt hơn xấu xí.
Tường minh thì tốt hơn ngầm định.
Đơn giản thì tốt hơn phức tạp.
Phức tạp thì tốt hơn rắc rối.
Bằng phẳng thì tốt hơn lồng ghép.
Rải rác thì tốt hơn dày đặc.
Tính dễ đọc rất đáng lưu tâm.
Mặc dù tính thực dụng đánh bật tính thuần túy,
thì trường hợp đặc biệt cũng không đủ đặc biệt đến nỗi phá vỡ quy tắc.
Lỗi thì không nên bao giờ lặng thinh mà bỏ qua,
trừ phi bắt nó câm lặng một cách tường minh.
Khi đối mặt với tính mơ hồ, hãy cự tuyệt lòng cám dỗ suy đoán.
Nên chỉ có một – và thà rằng chỉ có một – cách rõ ràng để làm điều đó,
mặc dù cách đó có lẽ ban đầu không hiển nhiên trừ phi bạn là người Hà Lan.
Bây giờ thì tốt hơn không bao giờ,
mặc dù không bao giờ thì thường là tốt hơn ngay bây giờ.
Nếu bản thực hiện mà khó giải thích, thì đó là một ý tưởng tồi.
Nếu bản thực hiện mà dễ giải thích, thì đó có lẽ là một ý tưởng hay.
Không gian tên là một ý tưởng rất chi là vĩ đại—hãy làm thế nhiều hơn!
Đó là những gì mà mình đã học được về Python qua ứng dụng học lập trình khá thú vị là SoloLearn. Còn bạn? Bạn dã học được những gì qua SoloLearn hay qua việc học Python? Cùng chia sẻ ở phía bình luận nhé.
Tái bút một chút. Vậy là còn vài ngày nữa thôi là chúng ta sẽ đón khoảnh khắc giao thừa và bước sang một năm mới năm Canh Tý rồi. Mình chúc mọi người có một năm mới thực sự bình an, vui vẻ và luôn thành công trong cuộc sống. Hẹn gặp lại các bạn vào năm mới nhé.