Home

Awesome

<p align="center"><img src="/images/logo.png" alt=""></p> <h1 align="center">What the f*ck Python! 😱</h1> <p align="center"> <a href="https://github.com/satwikkansal/wtfpython">English</a> | <a href="#">Tiếng Việt</a> </p> <p align="center">Cùng khám phá và tìm hiểu Python thông qua các đoạn mã khiến bạn bất ngờ.</p>

Các bản dịch tiếng nước ngoài khác: Tiếng Trung 中文 | Thêm bản dịch

Bạn có thể tham khảo các đoạn mã với: Chế độ trực quan | Giao diện dòng lệnh

Python là một ngôn ngữ cấp cao, với các mã được thông dịch thay vì biên dịch như các ngôn ngữ khác như C hay Java. Python có rất nhiều các tính năng giúp việc lập trình dễ dàng, thuận tiện. Tuy nhiên, các đoạn mã viết bằng Python thỉnh thoảng cho ra kết quả không rõ ràng, gây khó hiểu khi mới nhìn vào.

wtfpython được tạo ra với mong muốn giải thích chính xác cách hoạt động của các đoạn mã thoạt nhìn khó hiểu và các tính năng ít được biết tới trong Python.

Một vài ví dụ có thể không làm bạn quá ngạc nhiên, tuy vậy bạn sẽ khám phá được những điều hay ho về Python mà có thể bạn chưa từng biết tới. Học lập trình thông qua những ví dụ như vậy giúp bạn hiểu sâu hơn những thứ nằm bên trong của một ngôn ngữ lập trình, khi đó bạn sẽ thấy hứng thú hơn trong quá trình học.

Nếu độc giả là một lập trình viên có thâm niên, hãy thử thức mình với các đoạn mã sắp tới, cố gắng làm đúng mỗi thử thách ngay trong lần đầu tiên. Độc giả có thể đã thử quả một vài trong số các bài toán trước đó, đọc và làm các bài toán dưới đây có thể giúp bạn ôn lại chúng.

PS: Nếu bạn đã đọc bài này trước đó, bạn có thể muốn xem những thay đổi mới ở đây.

Nào ta bắt đầu ...

Những nội dung chính

<!-- Generated using "markdown-toc -i README.md --maxdepth 3"--> <!-- toc --> <!-- tocstop -->

Cấu trúc của các ví dụ

Tất cả các các ví dụ được trình bày với cấu trúc như sau:

▶ Một tiêu đề hấp dẫn

# Đoạn mã tạo dựng ví dụ.
# Đoạn mã chủ thể cần khám phá...

Kết quả (Các phiên bản Python):

>>> câu lệnh kích hoạt?
Một vài kết quả bất ngờ, không như mong đợi

(Có thể có hay không): Một dòng mô tả kết quả

💡 Giải thích:

# Đoạn mã tạo dựng ví dụ
# Trong trường hợp cần thiết, chúng tôi liệt kê thêm nhiều ví dụ khác để giúp bạn hiểu rõ hơn

Kết quả (Các phiên bản Python):

>>> trigger # some example that makes it easy to unveil the magic
>>> trigger # Một vài ví dụ giúp bạn hiểu các đoạn mã
# some justified output

Lưu ý: Tất cả các ví dụ đã được chứng minh chạy thành công trên trình thông dịch Python 3.5.2 chế độ tương tác, với các phiên bản Python khác các ví dụ sẽ vẫn chạy bình thường, ngoại trừ một số ví dụ chúng tôi sẽ lưu ý trước phần kết quả.

Cách dùng các ví dụ

Theo tôi, để học các ví dụ trong bài, bạn nên đọc theo trình tự thời gian, và đối với mỗi ví dụ hãy:

$ pip install wtfpython -U
$ wtfpython

👀 Các ví dụ

Chương 1: Hack não!

▶ Món khai vị! *

<!-- Example ID: d3d73936-3cf1-4632-b5ab-817981338863 --> <!-- read-only -->

Kí hiệu "con hà mã" ("Walrus" operator), được giới thiệu trong phiên bản Python 3.8 đã trở nên khá phổ biến vì một vài lý do. Hãy thử qua nó xem 1.

# Phiên bản Python 3.8+

>>> a = "wtf_walrus"
>>> a
'wtf_walrus'

>>> a := "wtf_walrus"
File "<stdin>", line 1
    a := "wtf_walrus"
      ^
SyntaxError: invalid syntax (Lỗi về cú pháp: Cú pháp không hợp lệ)

>>> (a := "wtf_walrus") # This works though
>>> a
'wtf_walrus'

2 .

# Phiên bản Python 3.8+

>>> a = 6, 9
>>> a
(6, 9)

>>> (a := 6, 9)
>>> a
6

>>> a, b = 6, 9 # Phân rã (unpacking) các giá trị, hay còn gọi là câu lệnh gán đa giá trị (multiple assignments)
>>> a, b
(6, 9)
>>> (a, b = 16, 19) # Có 
  File "<stdin>", line 1
    (a, b = 6, 9)
          ^
SyntaxError: invalid syntax (Lỗi cú pháp: cú pháp không hợp lệ)

>>> (a, b := 16, 19) # Câu lệnh này in ra một tuple có 3 phần tử không như mong đợi (đáng lẽ là 2 phần tử 16 và 19)
(6, 16, 19)

>>> a # a được được gán lại giá trị trước đó, nhưng giá trị phía dưới vẫn giữ nguyên, là sao?
6

>>> b 
16

💡 Giải thích

Ôn lại một chút về kí hiệu "con hà mã"

Kí hiệu con hà mã (:=) lần đầu tiên được giới thiệu trong phiên bản Python 3.8, nó hữu dụng khi bạn muốn gán giá trị cho các biến bên trong một biểu diễn (expression).

def some_func():
        # Giả định rằng ta thực hiện một vài phép tính tốn nhiều tài nguyên (thời gian, I/O) ở đây
        # time.sleep(1000)
        return 5

# Thay vì thực hiện việc kiểm tra kết quả trả về của hàm trên,
if some_func():
        print(some_func()) # Và gọi lại hàm đó trong thân điều kiện, nghĩa là thực hiện các tính toán trong hàm 2 lần.
# Hay tốt hơn, ta có thể tiết kiệm một lời gọi hàm thông qua việc lấy về giá trị trả về ở một lần gọi và thực hiện so sánh trên giá trị đó:
a = some_func()
if a:
    print(a)

# Dùng kĩ hiệu con hà mã bạn có thể viết ngắn gọn hơn như dưới đây, phép gán được sử dụng như mệnh đề điều kiện và ta có thể sử dụng biến được gán giá trị trong thân câu điều kiện if:
if a := some_func():
        print(a)

Kết quả (> 3.8):

5
5
5

Sử dụng kí hiệu con hà mã giúp ta rút ngắn được đoạn mã đi một dòng và tránh được việc gọi some_func hai lần.


▶ Strings thỉnh thoảng có thể khá oái oăm

<!-- Example ID: 30f1d3fc-e267-4b30-84ef-4d9e7091ac1a --->

1.

>>> a = "some_string"
>>> id(a)
140420665652016
>>> id("some" + "_" + "string") # Để ý rằng cả hai giá trị id đều giống nhau (140420665652016).
140420665652016

2.

>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True # a và b cùng trỏ tới một địa chỉ trong bộ nhớ

>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False # a và b không cùng trỏ tới một địa chỉ trong bộ nhớ

3.

>>> a, b = "wtf!", "wtf!"
>>> a is b # Áp dụng cho tất cả các phiên bản Python, ngoại trừ các phiên bản 3.7.x
True # a và b cùng trỏ tới một địa chỉ trong bộ nhớ

>>> a = "wtf!"; b = "wtf!"
>>> a is b # Kết quả là True hoặc False tuỳ thuộc vào môi trường bên chạy đoạn mã (python shell / ipython / as a script)
False
# Tạo một file tên some_file.py, chứa ba dòng code dưới đây:
a = "wtf!"
b = "wtf!"
print(a is b)

# Khi file này được chạy kết quả in ra là True

4.

Kết quả (< Python3.7 )

>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
True
>>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
False

Có gì đó sai sai?

💡Giải thích:


▶ Be careful with chained operations

<!-- Example ID: 07974979-9c86-4720-80bd-467aa19470d9 --->
>>> (False == False) in [False] # makes sense
False
>>> False == (False in [False]) # makes sense
False
>>> False == False in [False] # now what?
True

>>> True is False == False
False
>>> False is False is False
True

>>> 1 > 0 < 1
True
>>> (1 > 0) < 1
False
>>> 1 > (0 < 1)
False

💡 Giải thích:

As per https://docs.python.org/2/reference/expressions.html#not-in

Nếu a, b, c, ..., y, z là các biểu diễn (expressions) và op1, op2, ..., opN là các phép so sánh, khi đó op1 b op2 c ... y opN z tương đương với op1 b and b op2 c and ... y opN, ngoại trì việc mỗi biểu diễn được thực hiện hay đánh giá nhiều nhât một lần

Trong khi những điều ta thấy phía trên có thể hơi ngớ ngẩn đối với bạn, ta có thể làm những thứ thú vị hơn như a == b == c0 <= x <= 100.


▶ How not to use is operator

<!-- Example ID: 230fa2ac-ab36-4ad1-b675-5f5a1c1a6217 --->

Ví dụ dươi đây rất nổi tiếng trên Internet 1.

>>> a = 256
>>> b = 256
>>> a is b
True

>>> a = 257
>>> b = 257
>>> a is b
False

2.

>>> a = []
>>> b = []
>>> a is b
False

>>> a = tuple()
>>> b = tuple()
>>> a is b
True

3. Kết quả

>>> a, b = 257, 257
>>> a is b
True

Kết qủa (Chỉ áp dụng cho Python 3.7.x )

>>> a, b = 257, 257
>> a is b
False

💡 Giải thích:

Sự khác biệt giữa is==

** 256 là một đối tượng hiện hữu nhưng 257 lại không phải là một đối tượng hiện hữu.

Khi bạn khởi chạy python các số từ -5 tới 256 sẽ được cấp phát. Những sô nay được sử dụng rất nhiều, do đó việc cấp phát này là hợp lý. Tham khảo từ https://docs.python.org/3/c-api/long.html

Cách triển khai hiện hành của Python duy trì một mảng các đối tượng sô nguyên từ -5 tới 256, khi bạn tạo một số nguyên trong dải này bạn sẽ quay trở về lại một tham chiếu tới một đôi tượng tồn tại. Do vậy ta vẫn có thể thay đổi giá trị của 1.

>>> id(256)
10922528
>>> a = 256
>>> b = 256
>>> id(a)
10922528
>>> id(b)
10922528
>>> id(257)
140084850247312
>>> x = 257
>>> y = 257
>>> id(x)
140084850247440
>>> id(y)
140084850247344

Ở đây trình thông dịch không đủ thông minh khi thực thi y = 257 và nhận ra rằng chúng ta đã tạo một số nguyên có giá trị là 257, rồi, do đó nó tiếp tục tạo một đôi tượng khác trong bộ nhớ.

Một tối ưu tương tự áp dụng cho các đối tượng bất biến (immutable) khác như là các tuples. Bởi vì lists có thể biến đổi được, do đó ta hiểu tại sao [] is [] sẽ trả về False() is () sẽ trả về True. Điều này giải thích đoạn mã thứ hai. Nào hãy cùng đi qua ví dụ thứ 3.

** Cả ab đều trỏ về cùng một đối tượng khi được khởi tạo với cung một giá trị và trên cùng một dòng code** Kết quả

>>> a, b = 257, 257
>>> id(a)
140640774013296
>>> id(b)
140640774013296
>>> a = 257
>>> b = 257
>>> id(a)
140640774013392
>>> id(b)
140640774013488

▶ Hash brownies

<!-- Example ID: eb17db53-49fd-4b61-85d6-345c5ca213ff --->

1.

some_dict = {}
some_dict[5.5] = "JavaScript"
some_dict[5.0] = "Ruby"
some_dict[5] = "Python"

Kết quả:

>>> some_dict[5.5]
"JavaScript"
>>> some_dict[5.0] # "Python" chiếm lấy khoá (key) của "Ruby"?
"Python"
>>> some_dict[5] 
"Python"

>>> complex_five = 5 + 0j
>>> type(complex_five)
complex
>>> some_dict[complex_five]
"Python"

Thế quái nào mà toàn in ra Python?

💡 Giải thích


▶ Deep down, we're all the same.

<!-- Example ID: 8f99a35f-1736-43e2-920d-3b78ec35da9b --->
class WTF:
  pass

Kết quả:

>>> WTF() == WTF() # two different instances can't be equal
False
>>> WTF() is WTF() # identities are also different
False
>>> hash(WTF()) == hash(WTF()) # hashes _should_ be different as well
True
>>> id(WTF()) == id(WTF())
True

💡 Giải thích:

  class WTF(object):
    def __init__(self): print("I")
    def __del__(self): print("D")

Kết quả:

>>> WTF() is WTF()
I
I
D
D
False
>>> id(WTF()) == id(WTF())
I
D
I
D
True

Như bạn quan sát thấy, có sự khác biệt ở thứ tự tiêu hiểu các đối tượng, và đó tạo ra sự khác biệt.


▶ Vô trật tự trong trật tự *

<!-- Example ID: 91bff1f8-541d-455a-9de4-6cd8ff00ea66 --->
from collections import OrderedDict


dictionary[1] = 'a'; dictionary[2] = 'b';

ordered_dict = OrderedDict()
ordered_dict[1] = 'a'; ordered_dict[2] = 'b';

another_ordered_dict = OrderedDict()
another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a';

class DictWithHash(dict):
    """
    A dict that also implements __hash__ magic.
    """
    __hash__ = lambda self: 0

class OrderedDictWithHash(OrderedDict):
    """
    An OrderedDict that also implements __hash__ magic.
    """
    __hash__ = lambda self: 0

Kết quả

>>> dictionary == ordered_dict # Nếu a == b
True
>>> dictionary == another_ordered_dict # and b == c
True
>>> ordered_dict == another_ordered_dict # thế sao c != a ??
False

# ta biết răng set chỉ chứa các phần tử độc nhất,
# thử tạo một set chứa 3 từ điển phía trên xem sao...

>>> len({dictionary, ordered_dict, another_ordered_dict})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict' (Lỗi về kiểu: kiểu không thể hash được)

# Lỗi trên xảy ra là điều dê hiểu do từ điển không được tran bị __hash__, 
# sử dụng các lớp bọc (wrapper classes) ta xây dựng phía trên thử xem.
>>> dictionary = DictWithHash()
>>> dictionary[1] = 'a'; dictionary[2] = 'b';
>>> ordered_dict = OrderedDictWithHash()
>>> ordered_dict[1] = 'a'; ordered_dict[2] = 'b';
>>> another_ordered_dict = OrderedDictWithHash()
>>> another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a';
>>> len({dictionary, ordered_dict, another_ordered_dict})
1
>>> len({ordered_dict, another_ordered_dict, dictionary}) # xáo trộn thứ tự cá phần tử trong set
2

Cái quái gì đang xảy ra?

💡 Giải thích:


▶ Cố thêm chút nữa... *

<!-- Example ID: b4349443-e89f-4d25-a109-82616be9d41a --->
def some_func():
    try:
        return 'from_try'
    finally:
        return 'from_finally'

def another_func(): 
    for _ in range(3):
        try:
            continue
        finally:
            print("Finally!")

def one_more_func(): # A gotcha!
    try:
        for i in range(3):
            try:
                1 / i
            except ZeroDivisionError:
                # Let's throw it here and handle it outside for loop
                raise ZeroDivisionError("A trivial divide by zero error")
            finally:
                print("Iteration", i)
                break
    except ZeroDivisionError as e:
        print("Zero division error occurred", e)

Kết quả:

>>> some_func()
'from_finally'

>>> another_func()
Finally!
Finally!
Finally!

>>> 1 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero (Ngoại lệ sinh ra bởi chia một số cho số 0)

>>> one_more_func()
Iteration 0

💡 Giải thích:


▶ For what?

<!-- Example ID: 64a9dccf-5083-4bc9-98aa-8aeecde4f210 --->
some_string = "wtf"
some_dict = {}
for i, some_dict[i] in enumerate(some_string):
    i = 10

Kết quả:

>>> some_dict # An indexed dict appears.
{0: 'w', 1: 't', 2: 'f'}

💡 Giải thích:


▶ Sự khác biệt đến từ thời điểm đánh giá

<!-- Example ID: 6aa11a4b-4cf1-467a-b43a-810731517e98 --->

1.

array = [1, 8, 15]
# Một biểu diễn generator thông thường
gen = (x for x in array if array.count(x) > 0)
array = [2, 8, 22]

Kết quả:

>>> print(list(gen)) # Các giá trị khác đi đâu mất rồi?
[8]

2.

array_1 = [1,2,3,4]
gen_1 = (x for x in array_1)
array_1 = [1,2,3,4,5]

array_2 = [1,2,3,4]
gen_2 = (x for x in array_2)
array_2[:] = [1,2,3,4,5]

Kết quả:

>>> print(list(gen_1))
[1, 2, 3, 4]

>>> print(list(gen_2))
[1, 2, 3, 4, 5]

3.

array_3 = [1, 2, 3]
array_4 = [10, 20, 30]
gen = (i + j for i in array_3 for j in array_4)

array_3 = [4, 5, 6]
array_4 = [400, 500, 600]

Kết quả:

>>> print(list(gen))
[401, 501, 601, 402, 502, 602, 403, 503, 603]

💡 Lý giải


is not ... không phải là is (not ...)

<!-- Example ID: b26fb1ed-0c7d-4b9c-8c6d-94a58a055c0d --->
>>> 'something' is not None
True
>>> 'something' is (not None)
False

💡 Giải thích


▶ A tic-tac-toe where X wins in the first attempt!

<!-- Example ID: 69329249-bdcb-424f-bd09-cca2e6705a7a --->
# Khởi tạo một hàng
row = [""] * 3 #row i['', '', '']
# Và tạo một bảng gồm các hàng
board = [row] * 3

Kết quả:

>>> board
[['', '', ''], ['', '', ''], ['', '', '']]
>>> board[0]
['', '', '']
>>> board[0][0]
''
>>> board[0][0] = "X"
>>> board
[['X', '', ''], ['X', '', ''], ['X', '', '']]

Chúng ta đã gán "X" cho ba vị trí trong bảng này chăng?

💡 Giải thích:

Khi chúng ta khởi tạoi biến row, hình mô phỏng dưới đây cho ta biết những gì diễn ra trong bộ nhớ

image

Khi board được khởi tạo băng việc nhân bản row, minh hoạ phía dưới mô tả những gì diên ra trong bộ nhớ (mỗi thành phần của bảng board[0], board[1]board[2] là một tham chiếu tới cung một danh sách trỏ bởi row)

image

Chúng ta có thể tránh điều trên xảy ra bằng cách không dùng biến row để sinh ra board. (Tim hiểu thêm tại (https://github.com/satwikkansal/wtfpython/issues/68) )

>>> board = [['']*3 for _ in range(3)]
>>> board[0][0] = "X"
>>> board
[['X', '', ''], ['', '', ''], ['', '', '']]

▶ The sticky output function

<!-- Example ID: 4dc42f77-94cb-4eb5-a120-8203d3ed7604 --->

1.

funcs = []
results = []
for x in range(7):
    def some_func():
        return x
    funcs.append(some_func)
    results.append(some_func())  # Chú ý lời gọi hàm ở đây

funcs_results = [func() for func in funcs]

kết quả:

>>> results
[0, 1, 2, 3, 4, 5, 6]
>>> funcs_results
[6, 6, 6, 6, 6, 6, 6]

Ngay cả khi các giá trị x khác nhau trong mọi vòng lặp trước khi đặt some_func vào trong danh sách funcs, tất cả các hàm đều trả về 6.

2.

>>> powers_of_x = [lambda x: x**i for i in range(10)]
>>> [f(2) for f in powers_of_x]
[512, 512, 512, 512, 512, 512, 512, 512, 512, 512]

💡 Lý giải


▶ Bài toán con gà và quả trứng *

<!-- Example ID: 60730dc2-0d79-4416-8568-2a63323b3ce8 --->

1.

>>> isinstance(3, int)
True
>>> isinstance(type, object)
True
>>> isinstance(object, type)
True

Đâu là lớp cơ bản cuối cùng ? Còn nhiều thứ gây khó hiểu hơn nữa sau đây

2.

>>> class A: pass
>>> isinstance(A, A)
False
>>> isinstance(type, type)
True
>>> isinstance(object, object)
True

3.

>>> issubclass(int, object)
True
>>> issubclass(type, object)
True
>>> issubclass(object, type)
False

💡 Giải thích


▶ Các mối quan hệ của lơp con (subclass)

<!-- Example ID: 9f6d8cf0-e1b5-42d0-84a0-4cfab25a0bc0 --->

Kết quả:

>>> from collections import Hashable
>>> issubclass(list, object)
True
>>> issubclass(object, Hashable)
True
>>> issubclass(list, Hashable)
False

Mối quan hệ giữa các lớp con có tính bắc cầu không?(ví dụ, nếu A là lớp con của B, và B là lớp con của C, vậy A nên là lớp con của C)

💡 Lý giải:


▶ All-true-ation *

<!-- Example ID: dfe6d845-e452-48fe-a2da-0ed3869a8042 -->
>>> all([True, True, True])
True
>>> all([True, True, False])
False

>>> all([])
True
>>> all([[]])
False
>>> all([[[]]])
True

Lý do vì sao mà lúc thì True mà lúc thì lại False

💡 Giải thích:


▶ Dấu phẩy lạ lùng

<!-- Example ID: 31a819c8-ed73-4dcc-84eb-91bedbb51e58 --->

Kết quả (< 3.6):

>>> def f(x, y,):
...     print(x, y)
...
>>> def g(x=4, y=5,):
...     print(x, y)
...
>>> def h(x, **kwargs,):
  File "<stdin>", line 1
    def h(x, **kwargs,):
                     ^
SyntaxError: invalid syntax (Lỗi cú pháp không hợp lệ)

>>> def h(*args,):
  File "<stdin>", line 1
    def h(*args,):
                ^
SyntaxError: invalid syntax (Lỗi cú pháp không hợp lệ)

💡 Lý giải:


▶ Strings and the backslashes

<!-- Example ID: 6ae622c3-6d99-4041-9b33-507bd1a4407b --->

Kết quả:

>>> print("\"")
"

>>> print(r"\"")
\"

>>> print(r"\")
File "<stdin>", line 1
    print(r"\")
              ^
SyntaxError: EOL while scanning string literal

>>> r'\'' == "\\'"
True

💡 Giải thích


▶ not knot!

<!-- Example ID: 7034deb1-7443-417d-94ee-29a800524de8 --->
x = True
y = False

Kết quả:

>>> not x == y
True
>>> x == not y
  File "<input>", line 1
    x == not y
           ^
SyntaxError: invalid syntax (Lỗi về cú pháp)

💡 Giải thích:


▶ Các chuỗi rưỡi trích dẫn

<!-- Example ID: c55da3e2-1034-43b9-abeb-a7a970a2ad9e --->

Kết quả:

>>> print('wtfpython''')
wtfpython
>>> print("wtfpython""")
wtfpython
>>> # Các câu lệnh phía dưới gặp lỗi cú pháp `SyntaxError` khi thực thi
>>> # print('''wtfpython')
>>> # print("""wtfpython")
  File "<input>", line 3
    print("""wtfpython")
                        ^
SyntaxError: EOF while scanning triple-quoted string literal (Lỗi cú pháp khi sử lý chuỗi được bao bởi dấu trích dẫn)

💡 Giải thích:


▶ Có gì sai sai với các giá trị luận lý (booleans)?

<!-- Example ID: 0bba5fa7-9e6d-4cd2-8b94-952d061af5dd --->

1.

# Một ví dụ tính toán số lượng các giá trị luận lý và
# sô nguyên trong một danh sách lẫn lộn các kiểu phần tử khác nhau.
mixed_list = [False, 1.0, "some_string", 3, True, [], False]
integers_found_so_far = 0
booleans_found_so_far = 0

for item in mixed_list:
    if isinstance(item, int):
        integers_found_so_far += 1
    elif isinstance(item, bool):
        booleans_found_so_far += 1

Kết quả:

>>> integers_found_so_far
4
>>> booleans_found_so_far
0

2.

>>> some_bool = True
>>> "wtf" * some_bool
'wtf'
>>> some_bool = False
>>> "wtf" * some_bool
''

3.

def tell_truth():
    True = False
    if True == False:
        print("I have lost faith in truth!")

Kết quả (< 3.x):

>>> tell_truth()
I have lost faith in truth!

💡 Lý giải:


▶ Class attributes and instance attributes

<!-- Example ID: 6f332208-33bd-482d-8106-42863b739ed9 --->

1.

class A:
    x = 1

class B(A):
    pass

class C(A):
    pass

Kết quả:

>>> A.x, B.x, C.x
(1, 1, 1)
>>> B.x = 2
>>> A.x, B.x, C.x
(1, 2, 1)
>>> A.x = 3
>>> A.x, B.x, C.x # C.x thay đổi, nhưng B.x không thay đổi
(3, 2, 3)
>>> a = A()
>>> a.x, A.x
(3, 3)
>>> a.x += 1
>>> a.x, A.x
(4, 3)

2.

class SomeClass:
    some_var = 15
    some_list = [5]
    another_list = [5]
    def __init__(self, x):
        self.some_var = x + 1
        self.some_list = self.some_list + [x]
        self.another_list += [x]

Kết quả:

>>> some_obj = SomeClass(420)
>>> some_obj.some_list
[5, 420]
>>> some_obj.another_list
[5, 420]
>>> another_obj = SomeClass(111)
>>> another_obj.some_list
[5, 111]
>>> another_obj.another_list
[5, 420, 111]
>>> another_obj.another_list is SomeClass.another_list
True
>>> another_obj.another_list is some_obj.another_list
True

💡 Giải thích:


▶ Non-reflexive class method *

<!-- Example ID: 3649771a-f733-413c-8060-3f9f167b83fd -->
class SomeClass:
        def instance_method(self):
                pass
        
        @classmethod
        def class_method(cls):
                pass

Kết quả:

>>> SomeClass.instance_method is SomeClass.instance_method
True
>>> SomeClass.class_method is SomeClass.class_method
False
>>> id(SomeClass.class_method) == id(SomeClass.class_method)
True

💡 Giải thích:


▶ yielding None

<!-- Example ID: 5a40c241-2c30-40d0-8ba9-cf7e097b3b53 --->
some_iterable = ('a', 'b')

def some_func(val):
    return "something"

Kết quả (<= 3.7.x):

>>> [x for x in some_iterable]
['a', 'b']
>>> [(yield x) for x in some_iterable]
<generator object <listcomp> at 0x7f70b0a4ad58>
>>> list([(yield x) for x in some_iterable])
['a', 'b']
>>> list((yield x) for x in some_iterable)
['a', None, 'b', None]
>>> list(some_func((yield x)) for x in some_iterable)
['a', 'something', 'b', 'something']

💡 Giải thích:


▶ Yielding from... return! *

<!-- Example ID: 5626d8ef-8802-49c2-adbc-7cda5c550816 --->

1.

def some_func(x):
    if x == 3:
        return ["wtf"]
    else:
        yield from range(x)

Kết quả (> 3.3):

>>> list(some_func(3))
[]

Đáng lẽ phải hiển thị "wtf" chứ nhỉ? Có phải là do yield from? Cùng tìm hiểu thêm nào,

2.

def some_func(x):
    if x == 3:
        return ["wtf"]
    else:
        for i in range(x):
          yield i

Kết quả:

>>> list(some_func(3))
[]

Vẫn lại không in ra "wtf" .

💡 Giải thích:

"... return expr tron một generator tạo ra ngoại lệ StopIteration(expr) khi thoát ra từ generator."


▶ Tính phản xạ của Nan *

<!-- Example ID: 59bee91a-36e0-47a4-8c7d-aa89bf1d3976 --->

1.

a = float('inf')
b = float('nan')
c = float('-iNf')  # Các strings này không phân biệt hoa hay thường
d = float('nan')

Kết quả:

>>> a
inf
>>> b
nan
>>> c
-inf
>>> float('some_other_string')
ValueError: could not convert string to float: some_other_string (Lỗi giá trị: Không thể chuyển đổi từ string sang float)
>>> a == -c # inf==inf
True
>>> None == None # None == None
True
>>> b == d # nhưng nan!=nan
False
>>> 50 / a
0.0
>>> a / a
nan
>>> 23 + b
nan

2.

>>> x = float('nan')
>>> y = x / x
>>> y is y # định danh giống nhau (cùng trỏ về một đối tượng)
True
>>> y == y # Gía trị lại không bằng nhau
False
>>> [y] == [y] # Giá trị bằng nhau khi nằm ở trong một list
True

💡 Giải thích:

Do các định danh của xy khác nhau, do đó giá trị của chúng sẽ được so sánh, mà giá trị của chúng khác nhau trong ví dụ này; nên kết quả trả về là False. Cụ thể hơn, theo tiêu chuẩn của IEEE thì x f va y đểu có giá trị là nan khi được chuyển đổi qua float, NaN != NaN nên x != y, nhưng khi đặt trong một list thì định danh sẽ đc so sánh trước nên [x] == [y]


▶ Mutating the immutable!

<!-- Example ID: 15a9e782-1695-43ea-817a-a9208f6bb33d --->

Ví dụ dưới đây có vẻ tầm thường nếu bạn hiểu cách các tham chiếu (references) hoạt đông trong Python.

some_tuple = ("A", "tuple", "with", "values")
another_tuple = ([1, 2], [3, 4], [5, 6])

Kết quả:

>>> some_tuple[2] = "change this"
TypeError: 'tuple' object does not support item assignment (Lỗi về kiểu: đối tượng 'tuple' không hỗ trợ phép gán phần tử)
>>> another_tuple[2].append(1000) # Dòng này không bị lỗi
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000])
>>> another_tuple[2] += [99, 999]
TypeError: 'tuple' object does not support item assignment (Lỗi về kiểu: đối tượng 'tuple' không hỗ trợ phép gán phần tử)
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000, 99, 999])

Tôi đã nghĩ rằng các tuples thì bất biến (immutable) ...

💡 Giải thích:


▶ The disappearing variable from outer scope

<!-- Example ID: 7f1e71b6-cb3e-44fb-aa47-87ef1b7decc8 --->
e = 7
try:
    raise Exception()
except Exception as e:
    pass

Kết quả (Python 2.x):

>>> print(e)
# Không in ra kết quả nào cả

Kết quả (Python 3.x):

>>> print(e)
NameError: name 'e' is not defined (Lỗi tên biến không được định nghĩa)

💡 Giải thích:


▶ The mysterious key type conversion

<!-- Example ID: 00f42dd0-b9ef-408d-9e39-1bc209ce3f36 --->
class SomeClass(str):
    pass

some_dict = {'s': 42}

Kết quả:

>>> type(list(some_dict.keys())[0])
str
>>> s = SomeClass('s')
>>> some_dict[s] = 40
>>> some_dict # Giá trị mong đợi: Hai cặp khoá và giá trị khác nhau
{'s': 40}
>>> type(list(some_dict.keys())[0])
str

💡 Giải thích:


▶ Let's see if you can guess this?

<!-- Example ID: 81aa9fbe-bd63-4283-b56d-6fdd14c9105e --->
a, b = a[b] = {}, 5

Kết quả:

>>> a
{5: ({...}, 5)}

💡 Giải thích:

Tương tự là trong ví dụ của chúng ta (a[b][0] là cùng đối tượng với a)



Section: Slippery Slopes

▶ Modifying a dictionary while iterating over it

<!-- Example ID: b4e5cdfb-c3a8-4112-bd38-e2356d801c41 --->
x = {0: None}

for i in x:
    del x[i]
    x[i+1] = None
    print(i)

Kết quả (Áp dụng cho các phiên bản Python 2.7- Python 3.5):

0
1
2
3
4
5
6
7

Vòng lặp chạy đúng tám lần rồi dừng lại

💡 Giải thích:


▶ Stubborn del operation

<!-- Example ID: 777ed4fd-3a2d-466f-95e7-c4058e61d78e ---> <!-- read-only -->
class SomeClass:
    def __del__(self):
        print("Deleted!")

Kết quả: 1.

>>> x = SomeClass()
>>> y = x
>>> del x # this should print "Deleted!"
>>> del y
Deleted!

Có thể bạn đoán được làm sao mà __del__ không được gọi khi ta cố gắng xoá x trong lần đầu tiên. Hãy thử thêm 2.

>>> x = SomeClass()
>>> y = x
>>> del x
>>> y # check if y exists Kiểm tra y có tồn tại
<__main__.SomeClass instance at 0x7f98a1a67fc8>
>>> del y # Như lần trước, đáng lẽ kết quả nên là in ra "Deleted!"
>>> globals() # nhưng không, ta không có được kết quả như mong muốn. Cùng kiểm tra tất cả các biến toàn cục và xác nhận 
Deleted!
{'__builtins__': <module '__builtin__' (built-in)>, 'SomeClass': <class __main__.SomeClass at 0x7f98a1a5f668>, '__package__': None, '__name__': '__main__', '__doc__': None}

Ok giờ thì nó đã được xoá :confused:

💡 Giải thích:


▶ The out of scope variable

<!-- Example ID: 75c03015-7be9-4289-9e22-4f5fdda056f7 --->
a = 1
def some_func():
    return a

def another_func():
    a += 1
    return a

Kết quả:

>>> some_func()
1
>>> another_func()
UnboundLocalError: local variable 'a' referenced before assignment (tham chiếu tới 'a' trước khi gán giá trị)

💡 Giải thích:


▶ Deleting a list item while iterating

<!-- Example ID: 4cc52d4e-d42b-4e09-b25f-fbf5699b7d4e --->
list_1 = [1, 2, 3, 4]
list_2 = [1, 2, 3, 4]
list_3 = [1, 2, 3, 4]
list_4 = [1, 2, 3, 4]

for idx, item in enumerate(list_1):
    del item

for idx, item in enumerate(list_2):
    list_2.remove(item)

for idx, item in enumerate(list_3[:]):
    list_3.remove(item)

for idx, item in enumerate(list_4):
    list_4.pop(idx)

Kết quả:

>>> list_1
[1, 2, 3, 4]
>>> list_2
[2, 4]
>>> list_3
[]
>>> list_4
[2, 4]

Vì sao lại có kết quả là [2, 4]?

💡 Giải thích:

Sự khác biệt giữa del, remove, và pop:

Tại sao kết quả lại ra [2, 4]?


▶ Lossy zip of iterators *

<!-- Example ID: c28ed154-e59f-4070-8eb6-8967a4acac6d --->
>>> numbers = list(range(7))
>>> numbers
[0, 1, 2, 3, 4, 5, 6]
>>> first_three, remaining = numbers[:3], numbers[3:]
>>> first_three, remaining
([0, 1, 2], [3, 4, 5, 6])
>>> numbers_iter = iter(numbers)
>>> list(zip(numbers_iter, first_three)) 
[(0, 0), (1, 1), (2, 2)]
# so far so good, let's zip the remaining
>>> list(zip(numbers_iter, remaining))
[(4, 3), (5, 4), (6, 5)]

Phần tử 3 trong numbers đâu?

💡 Giải thích:


▶ Loop variables leaking out!

<!-- Example ID: ccec7bf6-7679-4963-907a-1cd8587be9ea --->

1.

for x in range(7):
    if x == 6:
        print(x, ': for x inside loop')
print(x, ': x in global')

Kết quả:

6 : for x inside loop
6 : x in global

Nhưng mà x chưa bao giờ được định nghĩa bên ngoài vòng lặp... 2.

# Lần này khởi tạo x trước
x = -1
for x in range(7):
    if x == 6:
        print(x, ': for x inside loop')
print(x, ': x in global')

Kết quả:

6 : for x inside loop
6 : x in global

3.

Kết quả (Python 2.x):

>>> x = 1
>>> print([x for x in range(5)])
[0, 1, 2, 3, 4]
>>> print(x)
4

Kết quả (Python 3.x):

>>> x = 1
>>> print([x for x in range(5)])
[0, 1, 2, 3, 4]
>>> print(x)
1

💡 Giải thích:


▶ Beware of default mutable arguments!

<!-- Example ID: 7d42dade-e20d-4a7b-9ed7-16fb58505fe9 --->
def some_func(default_arg=[]):
    default_arg.append("some_string")
    return default_arg

Kết quả:

>>> some_func()
['some_string']
>>> some_func()
['some_string', 'some_string']
>>> some_func([])
['some_string']
>>> some_func()
['some_string', 'some_string', 'some_string']

💡 Giải thích:


▶ Catching the Exceptions

<!-- Example ID: b5ca5e6a-47b9-4f69-9375-cda0f8c6755d --->
some_list = [1, 2, 3]
try:
    # Câu lệnh sau sẽ gây ra ngoại lệ ``IndexError``
    print(some_list[4])
except IndexError, ValueError:
    print("Caught!")

try:
    # Câu lệnh sau sẽ gây ra ngoại lệ ``ValueError``
    some_list.remove(4)
except IndexError, ValueError:
    print("Caught again!")

Kết quả (Python 2.x):

Caught!

ValueError: list.remove(x): x not in list

Kết quả (Python 3.x):

  File "<input>", line 3
    except IndexError, ValueError:
                     ^
SyntaxError: invalid syntax

💡 Giải thích


▶ Same operands, different story!

<!-- Example ID: ca052cdf-dd2d-4105-b936-65c28adc18a0 --->

1.

a = [1, 2, 3, 4]
b = a
a = a + [5, 6, 7, 8]

Kết quả:

>>> a
[1, 2, 3, 4, 5, 6, 7, 8]
>>> b
[1, 2, 3, 4]

2.

a = [1, 2, 3, 4]
b = a
a += [5, 6, 7, 8]

Kết quả:

>>> a
[1, 2, 3, 4, 5, 6, 7, 8]
>>> b
[1, 2, 3, 4, 5, 6, 7, 8]

💡 Giải thích:


▶ Name resolution ignoring class scope

<!-- Example ID: 03f73d96-151c-4929-b0a8-f74430788324 --->

1.

x = 5
class SomeClass:
    x = 17
    y = (x for i in range(10))

Kết quả:

>>> list(SomeClass.y)[0]
5

2.

x = 5
class SomeClass:
    x = 17
    y = [x for i in range(10)]

Kết quả (Python 2.x):

>>> SomeClass.y[0]
17

Kết quả (Python 3.x):

>>> SomeClass.y[0]
5

💡 Giải thích


▶ Needles in a Haystack *

<!-- Example ID: 52a199b1-989a-4b28-8910-dff562cebba9 --->

Tôi chưa bao giờ gặp một lập trình viên Python kinh nghiệm nào mà chưa gặp phải một trong những tình huống éo le dưới đây 1.

x, y = (0, 1) if True else None, None

Kết qủa:

>>> x, y  # Kết quả mong đợi (0, 1)
((0, 1), None)

2.

t = ('one', 'two')
for i in t:
    print(i)

t = ('one')
for i in t:
    print(i)

t = ()
print(t)

Kết quả:

one
two
o
n
e
tuple()

3.

ten_words_list = [
    "some",
    "very",
    "big",
    "list",
    "that"
    "consists",
    "of",
    "exactly",
    "ten",
    "words"
]

Kết quả

>>> len(ten_words_list)
9

4. Not asserting strongly enough

a = "python"
b = "javascript"

Kết quả:

# Gọi một câu lệnh assert với một thông điệp chỉ rõ lý do bị lỗi
>>> assert(a == b, "Both languages are different")
# Không thấy một ngoại lệ lỗi AssertionError 

5.

some_list = [1, 2, 3]
some_dict = {
  "key_1": 1,
  "key_2": 2,
  "key_3": 3
}

some_list = some_list.append(4) 
some_dict = some_dict.update({"key_4": 4})

Kết quả:

>>> print(some_list)
None
>>> print(some_dict)
None

6.

def some_recursive_func(a):
    if a[0] == 0:
        return 
    a[0] -= 1
    some_recursive_func(a)
    return a

def similar_recursive_func(a):
        if a == 0:
                return a
        a -= 1
        similar_recursive_func(a)
        return a

Kết quả:

>>> some_recursive_func([5, 0])
[0, 0]
>>> similar_recursive_func(5)
4

💡 Giải thích:


▶ Splitsies *

<!-- Example ID: ec3168ba-a81a-4482-afb0-691f1cc8d65a --->
# thực hiện câu lệnh này
>>> 'a'.split()
['a']

# cũng giống như
>>> 'a'.split(' ')
['a']

# nhưng khi chạy
>>> len(''.split())
0

# lại cho kết quả không giống nhau
>>> len(''.split(' '))
1

💡 Giải thích:


▶ Wild imports *

<!-- Example ID: 83deb561-bd55-4461-bb5e-77dd7f411e1c ---> <!-- read-only -->
# File: module.py

def some_weird_name_func_():
    print("works!")

def _another_weird_name_func():
    print("works!")

Kết quả

>>> from module import *
>>> some_weird_name_func_()
"works!"
>>> _another_weird_name_func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_another_weird_name_func' is not defined

💡 Giải thích:


▶ All sorted? *

<!-- Example ID: e5ff1eaf-8823-4738-b4ce-b73f7c9d5511 -->
>>> x = 7, 8, 9
>>> sorted(x) == x
False
>>> sorted(x) == sorted(x)
True

>>> y = reversed(x)
>>> sorted(y) == sorted(y)
False

💡 Giải thích:


▶ Midnight time doesn't exist?

<!-- Example ID: 1bce8294-5619-4d70-8ce3-fe0bade690d1 --->
from datetime import datetime

midnight = datetime(2018, 1, 1, 0, 0)
midnight_time = midnight.time()

noon = datetime(2018, 1, 1, 12, 0)
noon_time = noon.time()

if midnight_time:
    print("Time at midnight is", midnight_time)

if noon_time:
    print("Time at noon is", noon_time)

Kết quả (< 3.5):

('Time at noon is', datetime.time(12, 0))

Thời gian nửa đêm không được hiển thị

💡 Giải thêm:

Trước Python 3.5, giá trị luận lý cho đối tượng datetime.time được xem như là False nếu đối tượng này biểu diễn nửa đêm trong UTC. Code dễ sai khi sử dụng cú pháp if obj: để kiểm tra obj là null hay những giá trị tương tương với "rỗng".



Section: The Hidden treasures!

Phần này bao gồm những điều ít được biết tới về Python, những điều hấp dẫn này hầu hết những người mới bắt đầu như tôi đều không biết

▶ Okay Python, Can you make me fly?

<!-- Example ID: a92f3645-1899-4d50-9721-0031be4aec3f --->

Hãy bắt đầu nào

import antigravity

Kết quả: Sshh... Một bí mật lớn.

💡 Giải thích:


goto, but why?

<!-- Example ID: 2aff961e-7fa5-4986-a18a-9e5894bd89fe --->
from goto import goto, label
for i in range(9):
    for j in range(9):
        for k in range(9):
            print("I am trapped, please rescue!")
            if k == 2:
                goto .breakout # breaking out from a deeply nested loop
label .breakout
print("Freedom!")

Kết quả (Python 2.3):

I am trapped, please rescue!
I am trapped, please rescue!
Freedom!

💡 Giải thích:


▶ Brace yourself!

<!-- Example ID: 5c0c75f2-ddd9-4da3-ba49-c4be7ec39acf --->

Nếu bạn không thích sử dụng khoảng trắng để biểu thị các phạm vi, bạn có thể sử dụng phonng cách như trong ngôn ngữ C {} bằng cách import

from __future__ import braces

Kết quả:

  File "some_file.py", line 1
    from __future__ import braces
SyntaxError: not a chance

Các dấu ngoặc nhọn? Không được đâu! Nếu bạn nghĩ rằng điều gây thất vọng, sử dụng Java. Còn một điều ngạc nhiên nữa đây, bạn có thể tìm thấy ngoại lệ SyntaxError được khởi lên ở đâu trong module __future__ hay không (https://github.com/python/cpython/blob/master/Lib/__future__.py)?

💡 Giải thích:


▶ Let's meet Friendly Language Uncle For Life

<!-- Example ID: 6427fae6-e959-462d-85da-ce4c94ce41be --->

Output (Python 3.x)

>>> from __future__ import barry_as_FLUFL
>>> "Ruby" != "Python" # chả có gì phải nghi ngờ về câu lệnh so sánh này cả
  File "some_file.py", line 1
    "Ruby" != "Python"
              ^
SyntaxError: invalid syntax

>>> "Ruby" <> "Python"
True

Rồi! có thứ để xem.

💡 Giải thích:


▶ Even Python understands that love is complicated

<!-- Example ID: b93cad9e-d341-45d1-999c-fcdce65bed25 --->
import this

Nào, this là gì thế? this là tình yêu :heart:

Kết quả:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

this là Thiền của Python!

>>> love = this
>>> this is love
True
>>> love is True
False
>>> love is False
False
>>> love is not True or False
True
>>> love is not True or False; love is love  # Tình yêu thật phức tạp
True

💡 Giải thích:


▶ Yes, it exists!

<!-- Example ID: 4286db3d-1ea7-47c9-8fb6-a9a04cac6e49 --->

** Khối else của các vòng lặp .** Dưới đây là một ví dụ điển hình:

  def does_exists_num(l, to_find):
      for num in l:
          if num == to_find:
              print("Exists!")
              break
      else:
          print("Does not exist")

Kết quả:

>>> some_list = [1, 2, 3, 4, 5]
>>> does_exists_num(some_list, 4)
Exists! (Tồn tại)
>>> does_exists_num(some_list, -1)
Does not exist (Không tồn tại)

Khối else trong xử lý ngoại lệ. Một ví dụ,

try:
    pass
except:
    print("Exception occurred!!!")
else:
    print("Try block executed successfully...")

Kết quả:

Try block executed successfully...

💡 Giải thích:


▶ Ellipsis *

<!-- Example ID: 969b7100-ab3d-4a7d-ad7d-a6be16181b2b --->
def some_func():
    Ellipsis

Kết quả

>>> some_func()
# No output, No Error

>>> SomeRandomString
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'SomeRandomString' is not defined

>>> Ellipsis
Ellipsis

💡 Giải thích


▶ Inpinity

<!-- Example ID: ff473ea8-a3b1-4876-a6f0-4378aff790c1 --->

Việc viết sai chính tả là chủ ý. Kết quả (Python 3.x):

>>> infinity = float('infinity')
>>> hash(infinity)
314159
>>> hash(float('-inf'))
-314159

💡 Giải thích:


▶ Let's mangle

<!-- Example ID: 37146d2d-9e67-43a9-8729-3c17934b910c --->

1.

class Yo(object):
    def __init__(self):
        self.__honey = True
        self.bro = True

Kết quả:

>>> Yo().bro
True
>>> Yo().__honey
AttributeError: 'Yo' object has no attribute '__honey' (Đối tượng 'Yo' không có thuộc tính '__honey')
>>> Yo()._Yo__honey
True

2.

class Yo(object):
    def __init__(self):
        # Let's try something symmetrical this time
        self.__honey__ = True
        self.bro = True

Kết quả:

>>> Yo().bro
True

>>> Yo()._Yo__honey__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Yo' object has no attribute '_Yo__honey__' (Đối tượng 'Yo' không có thuộc tính '_Yo__honey__')

Tại sao Yo()._Yo__honey lại gây ra lỗi?

3.

_A__variable = "Some value"

class A(object):
    def some_func(self):
        return __variable # (biến này chưa được khởi tạo)

Kết quả:

>>> A().__variable
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__variable' (Đối tượng 'A' không có thuộc tính '__variable')

>>> A().some_func()
'Some value'

💡 Giải thích:



Section: Appearances are deceptive!

▶ Skipping lines?

<!-- Example ID: d50bbde1-fb9d-4735-9633-3444b9d2f417 --->

Kết quả:

>>> value = 11
>>> valuе = 32
>>> value
11

Cái quái gì thế?

Chú ý: Để làm ra kết quả như trên bạn chỉ cần sao chếp các câu lệnh và dán nó vào file hay shell.

💡 Giải thích

Một vài kí tự không phải là kí tự phương tây trông giống như các kí tự trong bảng chữ cái tiếng Anh nhưng lại được diễn giải khác bởi trình thông idhcj

>>> ord('е') # Kí tự cyrillic 'e' (Ye)
1077
>>> ord('e') # Kí tự latin 'e', được sử dụng trong tiếng Anh và trên các bàn phím chuẩn
101
>>> 'е' == 'e'
False

>>> value = 42 # latin e
>>> valuе = 23 # cyrillic 'e', Python 2.x interpreter would raise a `SyntaxError` here
>>> value
42

Hàm tích hợp sẵn ord() trả về mã Unicode của một kí tự code point, và bạn có thể thấy các mã khác nhau cho kí tự Cyrillic 'e' và kí tự Latin 'e' .


▶ Teleportation

<!-- Example ID: edafe923-0c20-4315-b6e1-0c31abfc38f5 --->
# Cài đặt thư viên numpy sử dụng `pip install numpy` trước
import numpy as np

def energy_send(x):
    # Khởi tạo một mảng numpy
    np.array([float(x)])

def energy_receive():
    # Trả về một mang numpy rỗng
    return np.empty((), dtype=np.float).tolist()

Kết quả:

>>> energy_send(123.456)
>>> energy_receive()
123.456

Có gì mới ở đây nào ?

💡 Giải thích:


▶ Well, something is fishy...

<!-- Example ID: cb6a37c5-74f7-44ca-b58c-3b902419b362 --->
def square(x):
    """
    A simple function to calculate the square of a number by addition.
    """
    sum_so_far = 0
    for counter in range(x):
        sum_so_far = sum_so_far + x
  return sum_so_far

Kết quả (Python 2.x):

>>> square(10)
10

Sao kết quả lại ra 100?

Chú ý: Nếu bạn không thực hiện lại được ví dụ trên, chạy thử file mixed_tabs_and_spaces.py thông qua shell.

💡 Explanation



Section: Miscellaneous

+= chạy nhanh hơn

<!-- Example ID: bfd19c60-a807-4a26-9598-4912b86ddb36 --->
# Sử dụng "+" để cộng 3 strings:
>>> timeit.timeit("s1 = s1 + s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100)
0.25748300552368164
# Sử dụng "+=" để cộng 3 strings:
>>> timeit.timeit("s1 += s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100)
0.012188911437988281

💡 Giải thích:


▶ Let's make a giant string!

<!-- Example ID: c7a07424-63fe-4504-9842-8f3d334f28fc --->
def add_string_with_plus(iters):
    s = ""
    for i in range(iters):
        s += "xyz"
    assert len(s) == 3*iters

def add_bytes_with_plus(iters):
    s = b""
    for i in range(iters):
        s += b"xyz"
    assert len(s) == 3*iters

def add_string_with_format(iters):
    fs = "{}"*iters
    s = fs.format(*(["xyz"]*iters))
    assert len(s) == 3*iters

def add_string_with_join(iters):
    l = []
    for i in range(iters):
        l.append("xyz")
    s = "".join(l)
    assert len(s) == 3*iters

def convert_list_to_string(l, iters):
    s = "".join(l)
    assert len(s) == 3*iters

Kết quả:

# Chạy các đoạn lệnh trong ipython shell sử dung %timeit để có kết quả dễ đọc hơn
# Bạn cũng có thể sử dụng module timeit trong python shell bình thường, như ví dụ dưới đây
# timeit.timeit('add_string_with_plus(10000)', number=1000, globals=globals())

>>> NUM_ITERS = 1000
>>> %timeit -n1000 add_string_with_plus(NUM_ITERS)
124 µs ± 4.73 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit -n1000 add_bytes_with_plus(NUM_ITERS)
211 µs ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit -n1000 add_string_with_format(NUM_ITERS)
61 µs ± 2.18 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit -n1000 add_string_with_join(NUM_ITERS)
117 µs ± 3.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> l = ["xyz"]*NUM_ITERS
>>> %timeit -n1000 convert_list_to_string(l, NUM_ITERS)
10.1 µs ± 1.06 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Bây giờ tăng số vòng lặp lên 10 lần

>>> NUM_ITERS = 10000
>>> %timeit -n1000 add_string_with_plus(NUM_ITERS) # Linear increase in execution time
1.26 ms ± 76.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit -n1000 add_bytes_with_plus(NUM_ITERS) # Quadratic increase
6.82 ms ± 134 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit -n1000 add_string_with_format(NUM_ITERS) # Linear increase
645 µs ± 24.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit -n1000 add_string_with_join(NUM_ITERS) # Linear increase
1.17 ms ± 7.25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> l = ["xyz"]*NUM_ITERS
>>> %timeit -n1000 convert_list_to_string(l, NUM_ITERS) # Linear increase
86.3 µs ± 2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

💡 Giải thích


▶ Minor Ones *

<!-- Example ID: f885cb82-f1e4-4daa-9ff3-972b14cb1324 --->

Đóng góp

Bạn có thể đóng góp cho wtfpython theo những cách dưới đây

Please see CONTRIBUTING.md for more details. Feel free to create a new issue to discuss things.

PS: Please don't reach out with backlinking requests, no links will be added unless they're highly relevant to the project.

Lời cám ơn

Ý tưởng và thiết kế của wtfpython lấy cảm hứng từ dự án tuyệt vời của Denys Dovhan's wtfjs. Cùng với đó là sự hỗ trợ tuyệt vời của những người yêu Python, giúp cho wtfpython có được như ngày hôm nay.

Một vài liên kết hay khác!

🎓 License

WTFPL 2.0

© Satwik Kansal

Chia sẻ cho bạn bè!

Nếu bạn thích wtfpython, bạn có thể chia sẻ các liên kết dưới đây cho bạn bè,

Twitter | Linkedin | Facebook

Bạn có cần bản pdf của wtf hay không?

I've received a few requests for the pdf (and epub) version of wtfpython. You can add your details here to get them as soon as they are finished.

Tôi nhận được một vài yêu cầu cho phiên bản pdf (và epub) của wtfpython. Nếu bạn muốn, bạn có thể thêm thông tin chi tiết của mình ở đây here để có phiên bản pdf sớm nhất.

That's all folks! For upcoming content like this, you can add your email here.

PS: On a sidenote, consider donating a dollar to plant a tree.