隨手扎
關於Python 3.8的象牙運算符(:=)
我沒想到一天會來寫個三篇😅。不過看完PEP 572 and The Walrus Operator後,對於象牙運算符(:=
),稍微產生了點不同樣的看法。至於稍早前覺得蠻新鮮的想法…可以去看看我上一篇。
此外,感謝Chang-Ning Tsai在社團分享該篇文章。
有爭議的象牙運算符(:=)
it is ambiguous for developers to distinguish the difference between the walrus operator (:=) and the equal operator (=). Even though sophisticated developers can use “:=” smoothly, they may concern the readability of their code.
最近在解LeetCode,在沒有這個賦予值的方法前,真覺得有些時候有點不方便。可是這個運算符在是否納入時,似乎有引起一些爭議。像是:=
可能難與閱讀,不過我覺得比較有問題的還是賦予值運算子(=
)和象牙運算子(:=
)的混搖,更正確的說,我是覺得兩者有點太像,這似乎有點違反Python的則學之一:「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.
Dutch怎麼了嗎?
繼續深入
Developers may confuse the difference between “:=” and “=.” In fact, they serve the same purpose, assigning somethings to variables. Why Python introduced “:=” instead of using “=”? What is the benefit of using “:=”? One reason is to reinforce the visual recognition due to a common mistake made by C/C++ developers. For instance,
int rc = access("hello_walrus", R_OK);
// rc is unintentionally assigned to -1
if (rc = -1) {
fprintf(stderr, "%s", strerror(errno));
goto end;
}
上面給出的例子中, if
當中的判斷是少了個=
,變成賦值,而非判斷是否相等。這是有點難用肉眼直接看出的錯誤,為了避免太過相像於==
,才選擇使用:=
。
如果是C/C++的話,上例如果編譯器能給出警告感覺就好除錯多了0_0
但就如前段所說,賦予值運算子(=
)和象牙運算子(:=
)感覺有點像,都有賦予變數值得能力。那麼按照哲學「There should be one– and preferably only one –obvious way to do it.」,何不全改成象牙運算子(:=
)?阿不過這絕對會是個大改變,就不知道社群如果真發展到Python 4的話(真的要像2到3那樣一次超級大改動的話),會怎麼討論與演變。況且現在字串格式化的方式也是多個並存,包含%
、.format
、f-strings
。那麼把象牙運算子(:=
)想成會回傳值得賦予值方式(強化版的賦予值?),好像未嘗不可?
嘗試
嘗試當成賦予值運算(Fail)
不行拉!直接會報錯!
所以兩者終究還是不同Orz,
仍然要小心使用(錯誤範例)
很想像C++這樣寫阿:
for(int i=0;i<10;){
// do something
// change i by manual
i++;
}
實際上我原本是想寫成while i := input("Please Input a number: "):
,只可惜Playground不給玩input
。然後不意外的,每次while
都會重新執行一次賦值,導致無窮迴圈。
下面這寫法會直接報錯:
[i := i+1 for i in range(5)] # invalid
同樣不允許直接賦予類別(class)或實例(instance)屬性,以下同樣會報錯:
class Example:
[(j := i) for i in range(5)] # invalid
# or
def __init__(self):
[(self.j := i) for i in range(5)] # invalid
但是可以:
class Example:
y = [ i for i in range(5)]
def __init__(self):
self.x = [(j := i) for i in range(5)]
print(j, self.x)
e = Example()
print(e.y)
Scopes
同樣沒有block-scope,不管是while
、if
、for
語句區塊內的,在這之後的同樣函式內部主體,一樣可以存取的到變數。
while i := -1:
print("innter", i)
if i < 0:
break
print("outer", i)
[(x := y) for y in range(5)]
print(x)
# print(y) # but not y
"""Output:
innter -1
outer -1
4
"""
這樣看來,存在區塊外後會消滅的,可能只有for in
語句了。
連
with open(file) as f:
的f都會在之後可以存取。
小節
整理來說,Python還是很活躍的在開發。有些開發方向或許有些人不認同,尤其在於更多人加入這個大家庭後更容易有。但每個人都可以參與討論,取得共識。並且也不是說這樣更新一定是對了,我記得也有看到一些特性是被移除後重新加回來(一時間找不到,也可能記錯了QAQ)。
但不管怎麼說,看到Python的發展還是讓我很興奮。最後,有任何錯誤之處還請指教!
LINE Pay贊助 信用卡小額贊助