python中的這些坑,早看早避免。python
說一說python中遇到的坑,躲坑看這一篇就夠了面試
def foo(num,age=[]):
age.append(num)
print("num",num)
return age
print(foo(1))
print(foo(2))
print(foo(3))
複製代碼
上面的代碼輸出的結果並非咱們預期的那樣,打印出三個數組[1],[2],[3]。
而是下面這樣.數組
num 1
[1]
num 2
[1, 2]
num 3
[1, 2, 3]
複製代碼
爲何會這樣呢,緣由就是參數age是一個列表,列表是一個可變對象,同時在做爲函數參數時,至關於全局變量,在函數預處理時就已經分配了內存空間。那麼咱們如何修改呢?
其實很簡單隻要不讓列表參數做爲列表,通常可變類型對象做爲參數的時候默認都是給定None,而後根據對象判斷是否爲空,若是爲空再去定義成列表,修改以下:bash
def foo(num, age=None):
if not age:
age = []
age.append(num)
print("num", num)
return age
print(foo(1))
print(foo(2))
print(foo(3))
複製代碼
在刷pythontip的時候遇到這道題,以爲頗有必要和你們普及下for。。else的用處,好了下面咱們開始:
輸出100之內的全部素數,素數之間以一個空格區分(注意,最後一個數字以後不能有空格)。微信
#在通常領域,對正整數n,若是用2到根號N之間的全部整數去除,均沒法整除,則n爲質數又叫素數。
import math
num = [] #存放1-100之間的素數
for i in range(2, 100):
for j in range(2, int(math.sqrt(i)) + 1):
if i % j == 0:
break
else:
num.append(i) #根據定義若是都沒法正常才加入
for index, i in enumerate(num):
if index == len(num) - 1:
print(i)
else:
print(i, end=" ")
複製代碼
根據關鍵語句「全部整數去除,均沒法整除,則n爲質數又叫素數。」,轉化成程序也就是說在全部的的數字都循環完了,還不能出才做爲質數,也就是最後的那個else,體現了這句話。由此能夠看出for。。else仍是挺重要的。閉包
看下面的代碼,猜測輸出結果:app
a = {}
a[1] = "A"
a[1.0] = "B"
a[2] = "C"
print(a)
複製代碼
若是不知道字典裏的鍵和hash有關,就不會知道結果是下面這個樣子函數
{1: 'B', 2: 'C'}
複製代碼
這是爲何呢?
由於,Python中的字典是經過檢查鍵值是否相等以及哈希值來肯定兩個鍵是否相同.
具備相同值的不可變對象在Python中始終具備相同的哈希值.
由於
1=1.0
因此hash(1)==hash(1.0).一樣的咱們知道python中的true相等,咱們試着
計算其hash值能夠看到hash(1)==hash(True)。
由此咱們能夠獲得以下等式:工具
hash(1)==hash(1.0)==hash(True)
複製代碼
由於只不可變對象才存在hash值因此 hash([])不存在。一樣咱們能夠推斷出學習
hash(0) == hash(False) == hash("")
複製代碼
根據PEP285中Review部分第6條所述,bool類實際上是從int類繼承而來.
print(isinstance(True, int))
複製代碼
python3中0=[]=()={}=None=False="",因此當咱們在判斷列表,或者字典字符串是否爲空的時候不用再使用 a==None,這樣的語句了。
a=[]
b={}
c=""
if not a:
print("a不爲空")
if not b:
print("b不爲空")
if not c:
print("c不爲空")
複製代碼
通常咱們寫if判斷的時候,咱們都寫成下面這種形式:
if type == "A":
print(1)
elif type == "B":
print(2)
複製代碼
像這樣的咱們須要寫好多重複代碼的程序,此時就要考慮是否優化了,針對這種狀況咱們能夠優先考慮字典。
my_dict = {"A":1, "B":2} #etc
print(my_dict[type])
複製代碼
另外咱們在使用給對象的屬性賦值的時候
class A():
def __init__(self,dicts):
self.name=dicts["name"]
self.age=dicts["age"]
self.sex=dicts["sex"]
self.hobby=dicts["hobby"]
if __name__ == '__main__':
dicts={"name":"lisa","age":23,"sex":"women","hobby":"hardstyle"}
a=A(dicts)
複製代碼
咱們看到咱們須要換取傳入的字典的各個鍵值,並建立鍵值同名一個屬性,這裏咱們只有4個還好,想象一下若是咱們傳入的字典有100個鍵。。。如何仍是這樣一個一個賦值不敢想不敢想,人家都寫完代碼了,你還在賦值有木有。。
其實一開始的那段代碼已經給出了答案,若是不會也不要緊,
下面咱們就來點pythonic的python。來解決這個問題。
上面代碼簡化爲:
class A():
def __init__(self,dicts):
self.__dict__.update(dicts)
print(self.__dict__)
if __name__ == '__main__':
dicts={"name":"lisa","age":23,"sex":"women","hobby":"hardstyle"}
a=A(dicts)
複製代碼
咱們觀察下面的代碼
ls = []
for x in range(5):
ls.append(lambda: x**2)
print(ls[0]())
print(ls[1]())
print(ls[2]())
複製代碼
咱們覺得它會輸出[0],[1],[4].但實際狀況是。。。。。
16
16
16
複製代碼
這是什麼鬼?
其實這和python的惰性求值有關。惰性求值,也就是延遲求值,表達式不會在它被綁定到變量以後就當即求值,而是等用到時再求值。x實際不在lambda的做用域中。只有當lambda被調用時,x的值纔會被傳給它。也就是最後的一次循環中x爲4,後面的ls[1],ls[1],ls[2],ls[3]實際都是16。同時這是面試常考的一個點,但願你們牢記。
這個問題考察了閉包。
執行文件的路徑和當前的路徑這是兩個概念
獲取文件的當前路徑時能夠的使用
import os
os.getcwd()
複製代碼
可是在須要執行的文件的獲取其執行路徑的時候就最好不要用這個了。
通常使用下面這種方式,動態的獲取路徑
import sys
sys.path[0]
複製代碼
eval("02")
複製代碼
會發生錯誤:
Traceback (most recent call last):
File "/demo/1.py", line 1, in <module>
eval("02")
File "<string>", line 1
02
^
SyntaxError: invalid token
複製代碼
python2的時候是這樣,覺得python3 True=1因此結果實際是同樣的。
因爲Python2中,True/False不是關鍵字,所以咱們能夠對其進行任意的賦值,這就致使程序在每次循環時都須要對True/False的值進行檢查;而對於1,則被程序進行了優化,然後不會再進行檢查。
Python3中,因爲True/False已是關鍵字了,不容許進行從新賦值,所以,其執行結果與while 1再也不有區別
對於長的字符串咱們通常使用"""多文本"""的形式,可是換行的時候容易致使哪裏出錯,此時能夠考慮在外面加個小括號,像這樣
("""多文本""")
複製代碼
做者實際上提供了個自動識別網頁編碼的代碼,在獲取res(請求的對象),獲取源碼以前使用
下面的代碼便可獲取正確的網站編碼。
res.encoding=res.apparent_encoding
複製代碼
更多工具使用以及python技巧,請關注公衆號:python學習開發。
若是您喜歡個人文章不防動動小手轉發一波,謝謝。點擊閱讀原文進入個人博客園,看代碼更方便。因爲人數超過100因此須要添加我微信:italocxa,而後拉您入羣。