Interesting in python(2)
brackets,Multiplication sign,backslash,Equal sign,Quotation marks
括號,乘號,反斜杠,判等號,引號
小括號與中括號
is not and is (not ...)
@python 3.6.7
this = 'this'
print(this is not None) # True
print(this is (not None)) #False
??上面應該很好理解,加了括號的not None
is True
。
列表生成式與生成器表達式
@python3.6.7
list1 = [1, 2, 3]
t1 = (x for x in list1 if list1.count(x) > 0) # iterator
list1 = [4, 2, 5]
print(list(t1))
# result
# [2]
list2 = [1, 2, 3]
t2 = [x for x in list2 if list2.count(x) > 0] # list
list2 = [4, 2, 5]
print(t2)
# result
# [1, 2, 3]
??在上面中代碼中,我們對列表list1,list2分別進行生成器操作和列表生成后都立馬進行了重新賦值,但生成器的結果好像有點出乎意料。
??這是因為在生成器表達式中,in
子句在聲明時執行,所以用來比較的x
還是1,2,3
;而if
條件子句則在運行時執行,所以此時條件判斷中list1已經變成了[4,2,5]
,能夠判斷成功的就只有2
了,而在列表生成式中則不受影響。
??另外一種情況:
@python 3.6.7
list1 = [1, 2, 3]
t1 = (x for x in list1) # iterator
list1 = [1, 2, 3, 4]
print(list(t1))
# 兩個list1不是同一個對象
# result
# [1, 2, 3]
list2 = [1, 2, 3]
t2 = (x for x in list2) # iterator
list2[:] = [1, 2, 3, 4]
print(list(t2))
# 由于切片操作賦值給相同的舊對象,兩個list2是同一個對象
# result
# [1, 2, 3, 4]
list2 = [1, 2, 3]
print(id(list2))
t2 = [x for x in list2] # list
list2[:] = [1, 2, 3, 4]
print(id(list2))
print(list(t2))
# 兩個list2是同一個對象,但用列表生成式就不會O(∩_∩)O哈哈~
# result
# 139771935690440
# 139771935690440
# [1, 2, 3]
??這里好像與我們之前說的in
在聲明的時候執行有點沖突,但其實不然,in
確實是在聲明的時候就執行,這句話意思是上面代碼中賦值給x
的是以前的list
對象。所以當兩個list
對象不同時,結果是原來list
對象的值;而切片操作是賦值給原來的對象,in
也操作原來的對象,所以就變成了賦值后的結果了。
??我們簡單總結一下,實際上如果用列表生成式,那么后一行代碼的操作不會影響它的執行結果,即使是改變同一個對象,因為列表生成式在這行代碼之后就已經完成;而生成器表達式的in
子句會使用同一個對象,若改變同一對象就會對in
造成影響,if
條件子句則在執行時會受后面代碼改動的影響,不管是否改動的是同一對象。因此我們可以大膽的寫出以下代碼來進行驗證:
@python 3.6.7
old_list = [1, 2, 3] # 1
t = (x for x in old_list if old_list.count(x) > 0)
old_list[:] = [4, 5, 6] # 2
print(list(t))
# 因為切片,old_list原有對象被重新賦值,對象不變
# 所以in使用的是: # 2 注釋的old_list的值
# if進行判斷使用的也是: # 2 注釋的old_list的值
# 所以 result
# [4, 5, 6]
??所以當我們在使用生成器表達式時,如果為了節省變量名而隨意在生成器表達式后面改動變量原來的值就很容易造成一些意想不到的結果。但也不要因此就不使用生成器,畢竟對于數量龐大的列表改用生成器是非常劃算的,我們需要注意的只是命名規范和編碼習慣,不要輕易改變原來已經存在對象的值。
方便的乘號 *
?
@python 3.6.7
single = [''] * 3 # single ['', '', '']
double = [single] * 2
# double [['', '', ''], ['', '', '']]
print(double[0][0]) # empty
double[0][0] = 'x'
print(double)
# result
# [['x', '', ''], ['x', '', '']]
??為啥明明我們只賦值了一個值,但是有兩個位置都有x
呢?
??那是因為當我們使用乘號的進行快速創建列表時,實際上只是增加了double
中single
的引用,即double[0]
,double[1]
引用的是同一個對象。
@python 3.6.7
single = [''] * 3
double = [single] * 2
print(id(double[0]), id(double[1]))
print(double[0] is double[1])
# result
# 140063679369736 140063679369736
# True
??所以毫無疑問賦值double[0][0]
實際上也是在對double[1][0]
進行操作。那么我們該如何消除這種影響,而做到我們真正想要的呢?下面有一種巧妙的辦法,就是不用中間變量進行引用。
@python 3.6.7
double = [[''] * 3 for _ in range(2)]
double[0][0] = 'x'
print(double)
# result
# [['x', '', ''], ['', '', '']]
反斜杠轉義和打印反斜杠
??眾所周知,反斜杠會對后面的字符進行轉移,所以\n
代表換行,\r
代表回車,那么如何打印字符串\n
呢?再加上一個反斜杠是很好的選擇。
@python 3.6.7
newline = '\\n'
print(newline)
# result
# \n
??也可以使用下面的方法:
@python 3.6.7
newline = r'\n'
print(newline)
# result
# \n
??但是請注意不要這樣使用:
@python 3.6.7
print(r'\n\') # SyntaxError
??因為在以r
開頭的原始字符串中,解釋器改變了反斜杠會解釋后面一個字符的行為,取而代之的是直接放行反斜杠后面的一個字符,所以上面的最后一個單引號被視為要打印的一部分。如果非要這樣使用,正確的寫法應該是這樣的:
@python 3.6.7
print(r'\n\'') # 再添加一個單引號
# result
# \n\'
小心運算符的優先級
@python 3.6.7
x = True
y = False
print(not x == y) # True
print(x == not y) # SyntaxError
??因為在python中==
運算符的優先級要高于not
運算符。所以not x == y
等價于not (x == y)
為True
;而x == not y
等價于(x == not) y
所以語法錯誤。
是拼接還是注釋
??我們都知道python多行注釋以三個引號為標記,但有些時候這只是字符串拼接。
@python 3.6.7
"""This is comment."""
print('''hello''') # hello
print("""hello again""") # hello again
print('hello''') # hello
print("hello again""") # hello again
print('''hello') # SyntaxError
print("""hello again") # SyntaxError
??如果你的編輯器有代碼高亮,實際上你已經可以看到不同之處。三個引號在前,那么解釋器會試圖再尋找三個相同的引號作為定界符,將其視為注釋或者可打印的字符串。而如果三個引號在后,實際上是隱式的字符串連接,'hello'''
意味著'hello' ''
,拼接一個空字符串,因此可以正確打印。