為什麼在python3里b=a=1是合理表達式,而print(a=1)卻不是。a=1為什麼沒有返回值?
lisp里每個表達式均有值,而python3里為什麼這種很平常的表達式卻沒有返回值呢?
首先,因為你在用C/C++的思維理解python。
沒有就是沒有,返回值的提法也不對,返回值是函數的結果。準確說應該是表達式值。
語言的語法是人定義的,賦值是assignment statement,不是expression,所以沒有值。
另外,在python裡面function_name(var=????)是有特殊的語義的,它指的是function_name的var參數的實參是????。
例如
def f(x, y):
return str(x) + str(y)
調用的時候我們可以
f(1, 2)
還可以寫全了
f(x=1, y=2)
還可以倒過來
f(y=2, x=1)
上面3個調用的結果全部是"12"
你用print(a=1)就意味著print有個形參是a。顯然就不對了。In [1]: def foo():
...: a = b = 1
...:
In [2]: from dis import dis
In [3]: dis(foo)
2 0 LOAD_CONST 1 (1)
3 DUP_TOP
4 STORE_FAST 0 (a)
7 STORE_FAST 1 (b)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
a = b = 1等價於 a = 1, b = 1
不要用C/C++來理解…不然給你個
if (1&<=a&<=10)
怎麼辦
你要理解為b=a=1是一個語句,而不是表達式。
樓上的各位解釋的已經很清楚了,總結一下就是:
python中賦值就是賦值,他不是一個表達式,也就不會返回一個表達式的值。
這樣做的一個好處是讓語法更加清晰。
在C中存在一個「行內賦值」的問題,舉個栗子:你打算判斷x的值是否等於1000, 如果等於1000則返回真,如果不等則返回假,正確的代碼應該是:#include&
void main(){
int x = 200;
if(x == 1000)
printf("true");
else
printf("false");
}
x的初始值為200,顯然不等於1000,那麼自然是執行else語句塊中的內容,返回假值:
#include&
void main(){
int x = 200;
if(x = 1000)
printf("true");
else
printf("false");
}
雖然x的初始值仍然是200, 但是這時候判斷語句被錯寫成了賦值表達式,而由於C是支持「行內賦值」的,並不會產生任何語法錯誤,於是 x = 1000 被成功執行,且表達式自身會有一個返回值,這個返回值為真,因此if語句塊中的內容被執行了,返回true:
而在python中,切記賦值就是賦值,是語句,不會有任何的返回值,類似這種」行內賦值「是不被允許的。倘若你嘗試用類似的方法,在 if/while/for 等等這樣的複合語句中使用 a=b 這樣的賦值語句,python解釋器就會毫不留情的拋出一個語法錯誤,像這樣:x = 200
if x = 1000:
print "true"
else:
print "false"
def greeting(title, name):
print "Hello, %(title)s %(name)s" % {"title":title, "name":name}
greeting("professor", "Li")
這樣title的值為"professor", name的值為」Li「,函數會輸出你想要的結果:
greeting(title="professor", name="Li")
or
greeting(name="Li", title="professor")
此時,傳遞參數的順序已經不重要了,python解釋器會根據顯示的賦值,來確定參數名和參數值的對應關係,調用的結果和按照位置傳入參數的結果是一樣的:
因此當你在調用 print(a=1) 的時候,實際上,python解釋器理解為給print()函數的形參a傳值,而不是你理解的「先個a賦值,再用print函數輸出a=1這個表達式的值」。遺憾的是,print() 函數並沒有叫這個名字的形參,於是解釋器拋出一個 TypeError 異常,告訴你它不認識變數a
OK,這種「關鍵字」形式的傳參有什麼意義呢?它的確有一些便利之處。例如你定義了一個函數,它有一些默認參數,像下面這個栗子一樣:def student_info(id, name, age, grade="G1", school="CUMT"):
info_str = """
id: %s;
name: %s;
age: %s;
grade: %s;
school: %s;
"""
print info_str % (id, name, age, grade, school)
if __name__ == "__main__":
student_info(1001, "Liu", 22)
student_info(1002, "Wang", 20, grade="G2")
student_info(1003, "Zhang", 21, school="PKU")
student_info() 這個函數有兩個默認參數,分別是grade(年級)和school(學校),默認值分別為"G1"和「CUMT」。
第一次調用,grade和school參數都使用了默認值;
第二次調用,grade我們指定了值為"G2",school參數仍然使用默認值;第三次調用,請注意,我們跳過了grade參數,給school參數傳了新的值"PKU",而grade參數仍然使用默認的"G1";
輸出結果如下:
為什麼在python3里b=a=1是合理表達式
鏈式賦值只是一種語法結構 他並不是跟cpp一樣"把1賦給a 再把a的值賦給b"
而是把1賦給b和a而print(a=1)卻不是
這句話的意思是把1賦給print的形參a 而不是像cpp那樣「把1賦給局部變數a 再把a的值傳進去」
a=1為什麼沒有返回值
a=1在cpp裡面是表達式(expression) 在py裡面叫語句(statement)
語句就像cpp的"return xxx;"一樣 不必要有值另外表達式的值也不叫返回值- Python的賦值語句是沒有返回值的,而且很多語言都沒有,這並不是編程語言界的規定或者慣例。
- 你的那個
print(a=1)
--------------------------------------------------------------------------
TypeError Traceback (most recent call last)
&in & ()
----&> 1 print(a=1)
TypeError: "a" is an invalid keyword argument for this function
默認會把a識別成為一個形參,但是print這個函數沒有a這個參數,所以會報錯,如果你想要輸出的是a=1這個表達式的值,你至少應該使用
print((a=1))
File "&
print((a=1))
^
SyntaxError: invalid syntax
這種情況下會報語法錯誤。
賦值語句沒有返回值,所以不是表達式,這是因為賦值語句不需要返回值, Python 既不是 C 也不是 Lisp。
即使有返回值的 Lisp ,返回值一般也是 "(),這就告訴你不要想用返回值做什麼事,其實和 Python 的思想是一樣的。
區別是 Python 用一個語法錯誤來防止程序員干蠢事而已。Why does Python assignment not return a value?鏈式賦值的邏輯不是先求值右側的表達式再賦給左側,僅僅是一種語法而已。下面可以看到,賦值的語句的解析顯然不是遞歸的。Simple statementsassignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
因為Python語言的設計者認為賦值最重要的作用是其副作用,不應該像表達式那樣有返回值.詳見:https://docs.python.org/3/faq/design.html?highlight=assignment#why-can-t-i-use-an-assignment-in-an-expression
。。。為了防止程序員出現if(x=1)這樣的錯誤而找不到bug所在,我們規定這樣寫是錯誤的
if( x = 1 ) { #do.... }
我覺得很難知道你是想先賦值再判斷x,還是想判斷 x 是否等於1,只是不小心漏掉了一個"等號"。
swift 更是從根本上解決了這一問題。我支持這一點。A: x = 1
if(x){ #do... }
B: if( x == 1 ){ #do... }
推薦閱讀:
※新手該學SQL還是Python?
※tornado cgi wsgi uwsgi之間的關係?
※用C寫Python擴展時哪些地方容易導致內存泄露?
※2017年,Web 後端出現了哪些新的思想和技術?
※(做生物信息的)你們是怎麼知道Python裡面sys.argv和getopt這種函數的?
TAG:Python |