Python 冷知識 - 註解、函數、布林值
匯整一下近期整理的 Python 冷知識,就是那些知道了也不一定會變高手的趣味事實(至少我覺得有趣)。
關於多行註解
有寫過 Python 的朋友應該知道,在 Python 是使用 #
符號來當做程式碼「註解(Comment)」寫,但你可能不知道 Python 並沒有「多行註解」的設計喔!
你可能會好奇這樣的寫法:
print("Hello")
"""
這是註解
這也是註解
這行還是註解
"""
print("World")
你看,用 3 個引號這個不就是多行註解了嗎?
如果你認為這是註解,那你可能誤解「註解」的設計了。
在 Python 這種 3 個引號的寫法並不是註解,它只是可以換行的「多行字串」而已。Python 本身只有單行註解,並沒有多行註解的設計。
的確,你可以拿多行字串來充當註解的效果,但不表示它就是註解,說到底它就只是個字串而已。通常使用多行文字充當註解的時候都不會指定變數給它,所以在 Python 直譯器的眼裡,它可能不會被編譯到 Bytecode 裡,以剛才的範例,編譯出來的結果是:
0 RESUME 0
1 LOAD_NAME 0 (print)
PUSH_NULL
LOAD_CONST 0 ('Hello')
CALL 1
POP_TOP
3 NOP
9 LOAD_NAME 0 (print)
PUSH_NULL
LOAD_CONST 1 ('World')
CALL 1
POP_TOP
RETURN_CONST 2 (None)
可以看到中間的多行文字直接消失了。
是說,如果把這個寫法放在類別或函數裡的第一行,可以造成 Docstring 的效果,也就是會幫類別或函數的 __doc__
屬性加料,但如果只是要做到 Docstring 的效果,一般的字串就能做到了,不一定需要用到多行字串。
Python 的發明人 Guido 曾經對多行註解這樣回覆過:
如 Guido 所說,的確是可以拿多行文字來「當做」多行註解,但這同時也表示 Python 本身就是沒有多行註解的設計,如果有的話就不需要用多行文字來「當做」了。
type() 不是函數
如果想要在 Python 裡印出某個資料的型別,可能會使用 type()
這個函數(或函式),如果想要做數字或字串轉型可能會用 int()
或 str()
函數,像這樣:
>>> type(123)
<class 'int'>
>>> int("123")
123
>>> str(123)
'123'
但是,事實上不管是 int
、str
或是 type
,它們在 Python 裡都是一個「類別(Class)」,只是剛好只傳一個引數給它的時候,它會做一些特別的事,例如做型別轉換或是印出它的型別,不信的話你可以用 type()
檢驗看看:
>>> type(int)
<class 'type'>
int
、str
、list
、dict
等類別都是一種叫做 type
的型別,這是因為 type
型別在 Python 是所有內建類別的 meta class,也就是所有內建型別都是一種 type
,包括 type
自己也是:
>>> type(type)
<class 'type'>
雖然它們用起來的手感像是呼叫函數,但在 Python 裡它們都是實實在在的類別 :)
關於布林值
在 Python 裡的布林型態(bool
)的 True
跟 False
,有些網路上的教學會說它們可以被轉型成數字 1
跟 0
。這樣的說法沒問題,但可能比較少人知道在 Python 裡布林值其實就是一種數字。不信的話,可以試著這樣做:
>>> bool.__base__
<class 'int'>
__base__
屬性可以取得類別的上層類別,所以可以看的出來 bool
的上層類別就是數字 int
,它們之間是有繼承關係的,所以布林值就是一種(kind of)整數。
而且,在 Python 裡的 True
跟 False
都只會存在一份,而且還是直接內建在 Python 直譯器裡。不管你怎麼建立新的布林值物件,它都會指向同一顆物件。例如:
>>> a = bool(123)
>>> b = bool("xyz")
>>> a is b
True
>>> a is True
True
可以看到它們就是同一顆物件。
另外,如果程式碼中使用了一看就知道的布林值判斷,例如:
if True:
print("這是真的")
因為這一定會發生,所以 Python 編譯的過程會直接把 if True
的判斷拿掉,只留下底下的程式碼。反之,如果是這樣寫:
if False:
print("這根本不會發生")
因為這一定不會發生,所以這段程式碼直接會被 Python 無視,根本不會被編譯成 Bytecode。
最後再補個冷知識,在 Python 2.2 之前,Python 其實是沒有布林型態的,早期的開發者常會使用 0 和 1 來代替布林值判斷,或是自己定義 True
和 False
,例如 True = 1
或是 False = 0
這樣的寫法。直到 PEP 285 提案之後才正式引入布林值的設計,並將上層類別設定成 int
類別。不過,在 Pytohn 2 時代,就算 PEP 285 提案已經通過,True
跟 False
還是可以被重新定義:
# 注意,這是 Python 2
>>> True = False
>>> print(True)
False
直到 Python 3 之後,True
跟 False
才變成保留字,無法被重新定義。