python开发中遇到的难题_初学者在Python开发中常见的问题(上)
前言:這篇文章主要介紹了Python程序員代碼編寫時應該避免的17個“坑”,也是Python程序員代碼編寫時應該避免的17個問題,如果有知友想要了解Python,文末有黑馬程序員的Python免費教程,需要的知友可以參考一下~如果喜歡請點贊哈
一、不要使用可變對象作為函數默認值
[url=]復制代碼[/url]代碼如下:
In [1]: def append_to_list(value, def_list=[]):
...: def_list.append(value)
...: return def_list
...:
In [2]: my_list = append_to_list(1)
In [3]: my_list
Out[3]: [1]
In [4]: my_other_list = append_to_list(2)
In [5]: my_other_list
Out[5]: [1, 2] # 看到了吧,其實我們本來只想生成[2] 但是卻把第一次運行的效果頁帶了進來
In [6]: import time
In [7]: def report_arg(my_default=time.time()):
...: print(my_default)
...:
In [8]: report_arg() # 第一次執行
1399562371.32
In [9]: time.sleep(2) # 隔了2秒
In [10]: report_arg()
1399562371.32 # 時間竟然沒有變
這2個例子說明了什么? 字典,集合,列表等等對象是不適合作為函數默認值的. 因為這個默認值實在函數建立的時候就生成了, 每次調用都是用了這個對象的”緩存”. 我在上段時間的分享python高級編程也說到了這個問題,這個是實際開發遇到的問題,好好檢查你學過的代碼, 也許只是問題沒有暴露
可以這樣改:
[url=]復制代碼[/url]代碼如下:
def append_to_list(element, to=None):
if to is None:
to = []
to.append(element)
return to
二、生成器不保留迭代過后的結果
[url=]復制代碼[/url]代碼如下:
In [12]: gen = (i for i in range(5))
In [13]: 2 in gen
Out[13]: True
In [14]: 3 in gen
Out[14]: True
In [15]: 1 in gen
Out[15]: False # 1為什么不在gen里面了? 因為調用1->2,這個時候1已經不在迭代器里面了,被按需生成過了
In [20]: gen = (i for i in range(5))
In [21]: a_list = list(gen) # 可以轉化成列表,當然a_tuple = tuple(gen) 也可以
In [22]: 2 in a_list
Out[22]: True
In [23]: 3 in a_list
Out[23]: True
In [24]: 1 in a_list # 就算循環過,值還在
Out[24]: True
三、lambda在閉包中會保存局部變量
[url=]復制代碼[/url]代碼如下:
In [29]: my_list = [lambda: i for i in range(5)]
In [30]: for l in my_list:
....: print(l())
....:
4
4
4
4
4
這個問題還是上面說的python高級編程中說過具體原因. 其實就是當我賦值給my_list的時候,lambda表達式就執行了i會循環,直到 i =4,i會保留
但是可以用生成器
[url=]復制代碼[/url]代碼如下:
In [31]: my_gen = (lambda: n for n in range(5))
In [32]: for l in my_gen:
....: print(l())
....:
0
1
2
3
4
也可以堅持用list:
[url=]復制代碼[/url]代碼如下:
In [33]: my_list = [lambda x=i: x for i in range(5)] # 看我給每個lambda表達式賦了默認值
In [34]: for l in my_list:
....: print(l())
....:
0
1
2
3
4
有點不好懂是吧,在看看python的另外一個魔法:
[url=]復制代碼[/url]代碼如下:
In [35]: def groupby(items, size):
....: return zip(*[iter(items)]*size)
....:
In [36]: groupby(range(9), 3)
Out[36]: [(0, 1, 2), (3, 4, 5), (6, 7, 8)]
一個分組的函數,看起來很不好懂,對吧? 我們來解析下這里
[url=]復制代碼[/url]代碼如下:
In [39]: [iter(items)]*3
Out[39]:
[,
,
] # 看到了吧, 其實就是把items變成可迭代的, 重復三回(同一個對象哦), 但是別忘了,每次都.next(), 所以起到了分組的作用
In [40]: [lambda x=i: x for i in range(5)]
Out[40]:
[>,
>,
>,
>,
>] # 看懂了嗎?
四、在循環中修改列表項
[url=]復制代碼[/url]代碼如下:
In [44]: a = [1, 2, 3, 4, 5]
In [45]: for i in a:
....: if not i % 2:
....: a.remove(i)
....:
In [46]: a
Out[46]: [1, 3, 5] # 沒有問題
In [50]: b = [2, 4, 5, 6]
In [51]: for i in b:
....: if not i % 2:
....: b.remove(i)
....:
In [52]: b
Out[52]: [4, 5] # 本來我想要的結果應該是去除偶數的列表
思考一下,為什么 – 是因為你對列表的remove,影響了它的index
[url=]復制代碼[/url]代碼如下:
In [53]: b = [2, 4, 5, 6]
In [54]: for index, item in enumerate(b):
....: print(index, item)
....: if not item % 2:
....: b.remove(item)
....:
(0, 2) # 這里沒有問題 2被刪除了
(1, 5) # 因為2被刪除目前的列表是[4, 5, 6], 所以索引list[1]直接去找5, 忽略了4
(2, 6)
五、IndexError - 列表取值超出了他的索引數
[url=]復制代碼[/url]代碼如下:
In [55]: my_list = [1, 2, 3, 4, 5]
In [56]: my_list[5] # 根本沒有這個元素
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
in ()
----> 1 my_list[5]
IndexError: list index out of range # 拋異常了
In [57]: my_list[5:] # 但是可以這樣, 一定要注意, 用好了是trick,用錯了就是坑啊
Out[57]: []
六、重用全局變量
[url=]復制代碼[/url]代碼如下:
In [58]: def my_func():
....: print(var) # 我可以先調用一個未定義的變量
....:
In [59]: var = 'global' # 后賦值
In [60]: my_func() # 反正只要調用函數時候變量被定義了就可以了
global
In [61]: def my_func():
....: var = 'locally changed'
....:
In [62]: var = 'global'
In [63]: my_func()
In [64]: print(var)
global # 局部變量沒有影響到全局變量
In [65]: def my_func():
....: print(var) # 雖然你全局設置這個變量, 但是局部變量有同名的, python以為你忘了定義本地變量了
....: var = 'locally changed'
....:
In [66]: var = 'global'
In [67]: my_func()
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
in ()
----> 1 my_func()
in my_func()
1 def my_func():
----> 2 print(var)
3 var = 'locally changed'
4
UnboundLocalError: local variable 'var' referenced before assignment
In [68]: def my_func():
....: global var # 這個時候得加全局了
....: print(var) # 這樣就能正常使用
....: var = 'locally changed'
....:
In [69]: var = 'global'
In [70]:
In [70]: my_func()
global
In [71]: print(var)
locally changed # 但是使用了global就改變了全局變量
七、拷貝可變對象
[url=]復制代碼[/url]代碼如下:
In [72]: my_list1 = [[1, 2, 3]] * 2
In [73]: my_list1
Out[73]: [[1, 2, 3], [1, 2, 3]]
In [74]: my_list1[1][0] = 'a' # 我只修改子列表中的一項
In [75]: my_list1
Out[75]: [['a', 2, 3], ['a', 2, 3]] # 但是都影響到了
In [76]: my_list2 = [[1, 2, 3] for i in range(2)] # 用這種循環生成不同對象的方法就不影響了
In [77]: my_list2[1][0] = 'a'
In [78]: my_list2
Out[78]: [[1, 2, 3], ['a', 2, 3]]
八、python多繼承(C3)
[url=]復制代碼[/url]代碼如下:
In [1]: class A(object):
...: def foo(self):
...: print("class A")
...:
In [2]: class B(object):
...: def foo(self):
...: print("class B")
...:
In [3]: class C(A, B):
...: pass
...:
In [4]: C().foo()
class A # 例子很好懂, C繼承了A和B,從左到右,發現A有foo方法,返回了
看起來都是很簡單, 有次序的從底向上,從前向后找,找到就返回. 再看例子:
[url=]復制代碼[/url]代碼如下:
In [5]: class A(object):
...: def foo(self):
...: print("class A")
...:
In [6]: class B(A):
...: pass
...:
In [7]: class C(A):
...: def foo(self):
...: print("class C")
...:
In [8]: class D(B,C):
...: pass
...:
In [9]: D().foo()
class C # ? 按道理, 順序是 D->B->A,為什么找到了C哪去了
這也就涉及了MRO(Method Resolution Order):
[url=]復制代碼[/url]代碼如下:
In [10]: D.__mro__
Out[10]: (__main__.D, __main__.B, __main__.C, __main__.A, object)
簡單的理解其實就是新式類是廣度優先了, D->B, 但是發現C也是繼承A,就先找C,最后再去找A。
向大家推薦兩套免費黑馬程序員Python經典入門教程,喜歡的可以收藏一下或者推薦給身邊的朋友:
總結
以上是生活随笔為你收集整理的python开发中遇到的难题_初学者在Python开发中常见的问题(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一加10T渲染图曝光:独特后摄模组设计
- 下一篇: python白森_氧气恋人