python的坑–你知道嗎?
python的坑–你知道嗎?
1.列表的坑
坑的地方是:因為列表用pop之後,後面的索引都會自動減一
# 列表的坑之一
list1 = ['python','java','php','c','c++','c#','ruby']
# 將索引為奇數的元素刪除 ['java','c','c#']
list2 = []
for item in list1:
if list1.index(item) % 2 != 1:
list1.pop(list1.index(item))
print(list1) # ['java', 'php', 'c++', 'c#']
# 這是因為列表用pop之後,後面的索引都會自動減一
# 正確的操作如下:
# 切片
list1 = ['python','java','php','c','c++','c#','ruby']
list2 = list1[1::2]
print(list2) #['java','c','c#']
# 賦值到其他的空列表
list1 = ['python','java','php','c','c++','c#','ruby']
list2 = []
for i in list1:
if list1.index(i)%2==0:
list2.append(i)
print(list2) # ['java','c','c#']
# 倒序刪除
list1 = ['python','java','php','c','c++','c#','ruby']
for i in range(len(list1)-1,-1,-1):
if i % 2 == 0:
del li[i]
print(list1) # ['java','c','c#']
2.默認參數的陷阱
# def func(name, sex='男'):
# print(name)
# print(sex)
#
#
# func('zhouqian')
# 輸出的結果為:
# zhouqian
# 男
上面的程式碼是運行正常的,彷彿默認參數並沒有什麼坑。但是我們用下面的例子就知道了。默認參數的陷阱只針對默認參數是可變的數據類型。
# def func(name, alist=[]):
# alist.append(name)
# return alist
#
#
# ret = func('zhouqian')
# print(ret, id(ret)) # ['zhouqian'] 2135732081224
# ret2 = func('太白金星')
# print(ret2, id(ret2))# 按理說是['太白金星'],但是實際上輸出['zhouqian', '太白金星'] 2135732081224
# print(func('zhouqian'))
# ['zhouqian'] 2135732081224
# ['zhouqian', '太白金星'] 2135732081224
通過id可知,默認參數是列表的話在記憶體中是共用同一個地址。只要調用了這個函數,那麼就會在同一個地址後面操作這個元素。如果你的默認參數是可變的數據類型,那麼無論你調用多少次函數,這個默認參數指向的都是同一個地址。如果你給可變的數據類型傳一個值,那麼就不會用原來默認的,就用這個傳值的。
下面我們用兩個python的面試題來講解默認參數是可變數據類型的坑。
面試題1:
def func(a, alist=[]):
alist.append(a)
return alist
print(func(10, )) # [10]
print(func(20, [])) # [20]
print(func(100, )) # [10,100]
# 上面的類似於下面的程式碼:
# l1 = []
# l1.append(10)
# print(l1) # [10]
# l2 = []
# l2.append(20)
# print(l2) # [20]
# l1.append(100)
# print(l1) # [10,100]
面試題2:
def func(a, alist=[]):
alist.append(a)
return alist
ret1 = func(10, ) # 這裡的值是alist(id 1564531154864)
ret2 = func(20, []) # 這裡的值是alist (id 4648456151995)
ret3 = func(100, ) # 這裡的值是alist (id 1564531154864)
print(ret1) # [10, 100]
print(ret2) # [20]
print(ret3) # [10, 100]
# 上面的類似於下面的程式碼:
# l1 = []
# l1.append(10)
# l2 = []
# l2.append(20)
# l1.append(100)
# ret1 = l1
# ret2 = l2
# ret3 = l1
# print(ret1) # [10,100]
# print(ret2) # [20]
# print(ret3) # [10,100]
3.局部作用域的陷阱
# count = 1
# def func():
# count += 1
# print(count)
# # UnboundLocalError: local variable 'count' referenced before assignment
# func()
# 解釋:2.局部作用域不能改變全局作用域的變數。當python解釋器讀取到局部作用域時,發現你對一個變數進行了修改的操作,解釋器會認為你在局部作用域已經定義過這個局部變數,他就從局部找這個局部變數,報錯了。
# 局部和全局作用域的詳細解析
# 1.局部作用域可以獲得到全局作用域中使用變數,重新創建變數,操作變數的賦值,可以用來對變數進行操作,改變變數的值。
# 2.局部作用域不能改變全局作用域的變數。當python解釋器讀取到局部作用域時,發現你對一個變數進行了修改的操作,解釋器會認為你在局部作用域已經定義過這個局部變數,他就從局部找這個局部變數,報錯了。
# 3.但是全局作用域不可以獲得局部作用域,不能操作局部作用域的變數,不能操作局部作用域的變數值。
# count = 1
#
# 在函數中,如果你定義了一個變數,但是在定義這個變數之前對其引用了,那麼解釋器認為語法問題。
# 你應該使用之前的先定義後引用。
# def func():
# # 先引用後定義。報錯
# print(count) # UnboundLocalError: local variable 'count' referenced before assignment
# count = 3
#
# func()
# 解釋:在函數中,如果你定義了一個變數,但是在定義這個變數之前對其引用了,那麼解釋器認為語法問題,你應該使用之前的先定義後引用。
# 以下兩個程式碼是不會報錯的。可以正常運行輸出結果。
# count = 1
#
#
# def func():
# print(count) # 1
# # count = 3 # 將count=3刪除/注釋掉就不會報錯
#
#
# func()
# count = 1
#
#
# def func():
# count = 3
# print(count) # 3
#
#
# func()
4.補充知識點:global和nonlocal
# global和nonlocal
# 1.在局部作用域聲明一個全局變數
# name = 'alex'
# def func():
# name = 'AndreasZhou'
# print(name)
# func()
# print(name)
# 輸出的結果為:
# AndreasZhou
# alex
# 解析:全局變數是從全局名稱空間和內置名稱空間中取值。局部變數是從局部名稱作用域、全局名稱作用域和內置名稱作用域取值。
# 局部名稱作用域---》全局名稱作用域---》內置名稱作用域取值,單向不可逆。
# def func():
# name = 'AndreasZhou'
# print(name)
# func() # AndreasZhou
# print(name) # NameError: name 'name' is not defined
# 輸出的結果為:
# AndreasZhou
# NameError: name 'name' is not defined
# name = 'zhouqian'
# def func():
# global name
# name = 'AndreasZhou'
# print(name)
# func()
# print(name)
# 輸出的結果為:
# AndreasZhou
# AndreasZhou
# def func():
# global name
# name = '太白金星'
# print(name)
# print(name)
# func()
# 輸出的結果為:
# NameError: name 'name' is not defined
# # 2.修改一個全局變數
# count = 1
# def func():
# # print(count) SyntaxError: name 'count' is used prior to global declaration
# global count
# count += 1
# print(count) # 1
# func()
#
# print(count) # 2
# nonlocal
# 1.不能夠操作全局變數
# count = 1
# def func():
# nonlocal count # SyntaxError: no binding for nonlocal 'count' found
# count += 1
# func()
# 2.局部作用域:內層函數對外層函數的局部變數進行修改
# def wrapper():
# count = 1
# def inner():
# count+=1 # UnboundLocalError: local variable 'count' referenced before assignment
# inner()
# wrapper()
def wrapper():
count = 1
def inner():
nonlocal count
count += 1
print(count) # 1
inner()
print(count) # 2
wrapper()