1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Python開發(fā)者最常犯的10個錯誤

        共 7562字,需瀏覽 16分鐘

         ·

        2022-07-27 18:51

        ↑ 關(guān)注 + 星標(biāo) ,每天學(xué)Python新技能

        后臺回復(fù)【大禮包】送你Python自學(xué)大禮包


        摘要:Python是一門簡單易學(xué)的編程語言,語法簡潔而清晰,并且擁有豐富和強(qiáng)大的類庫。在日常開發(fā)中,開發(fā)者很容犯一些低級的錯誤,本文總結(jié)了開發(fā)者最容易犯的10個錯誤。


        Python是一門簡單易學(xué)的編程語言,語法簡潔而清晰,并且擁有豐富和強(qiáng)大的類庫。與其它大多數(shù)程序設(shè)計(jì)語言使用大括號不一樣 ,它使用縮進(jìn)來定義語句塊。


        在平時的工作中,Python開發(fā)者很容易犯一些小錯誤,這些錯誤都很容易避免,本文總結(jié)了Python開發(fā)者最常犯的10個錯誤,一起來看下,不知你中槍了沒有。



        1.濫用表達(dá)式作為函數(shù)參數(shù)默認(rèn)值


        Python允許開發(fā)者指定一個默認(rèn)值給函數(shù)參數(shù),雖然這是該語言的一個特征,但當(dāng)參數(shù)可變時,很容易導(dǎo)致混亂,例如,下面這段函數(shù)定義:

        >>> def foo(bar=[]):        # bar is optional and defaults to [] if not specified
        ... bar.append("baz") # but this line could be problematic, as we'll see...
        ... return bar

        在上面這段代碼里,一旦重復(fù)調(diào)用foo()函數(shù)(沒有指定一個bar參數(shù)),那么將一直返回'bar',因?yàn)闆]有指定參數(shù),那么foo()每次被調(diào)用的時候,都會賦予[]。下面來看看,這樣做的結(jié)果:

        >>> foo()
        ["baz"]
        >>> foo()
        ["baz", "baz"]
        >>> foo()
        ["baz", "baz", "baz"]

        解決方案:

        >>> def foo(bar=None):
        ... if bar is None: # or if not bar:
        ... bar = []
        ... bar.append("baz")
        ... return bar
        ...
        >>> foo()
        ["baz"]
        >>> foo()
        ["baz"]
        >>> foo()
        ["baz"]

        2.錯誤地使用類變量


        先看下面這個例子:

        >>> class A(object):
        ... x = 1
        ...
        >>> class B(A):
        ... pass
        ...
        >>> class C(A):
        ... pass
        ...
        >>> print A.x, B.x, C.x
        1 1 1

        這樣是有意義的:

        >>> B.x = 2
        >>> print A.x, B.x, C.x
        1 2 1

        再來一遍:

        >>> A.x = 3
        >>> print A.x, B.x, C.x
        3 2 3

        僅僅是改變了A.x,為什么C.x也跟著改變了。


        在Python中,類變量都是作為字典進(jìn)行內(nèi)部處理的,并且遵循方法解析順序(MRO)。在上面這段代碼中,因?yàn)閷傩詘沒有在類C中發(fā)現(xiàn),它會查找它的基類(在上面例子中只有A,盡管Python支持多繼承)。換句話說,就是C自己沒有x屬性,獨(dú)立于A,因此,引用 C.x其實(shí)就是引用A.x。


        3.為異常指定不正確的參數(shù)


        假設(shè)代碼中有如下代碼:

        >>> try:
        ... l = ["a", "b"]
        ... int(l[2])
        ... except ValueError, IndexError: # To catch both exceptions, right?
        ... pass
        ...
        Traceback (most recent call last):
        File "<stdin>", line 3, in <module>
        IndexError: list index out of range

        問題在這里,except語句并不需要這種方式來指定異常列表。然而,在Python 2.x中,except Exception,e通常是用來綁定異常里的 第二參數(shù),好讓其進(jìn)行更進(jìn)一步的檢查。因此,在上面這段代碼里,IndexError異常并沒有被except語句捕獲,異常最后被綁定 到了一個名叫IndexError的參數(shù)上。


        在一個異常語句里捕獲多個異常的正確方法是指定第一個參數(shù)作為一個元組,該元組包含所有被捕獲的異常。與此同時,使用as關(guān)鍵字來保證最大的可移植性,Python 2和Python 3都支持該語法。

        >>> try:
        ... l = ["a", "b"]
        ... int(l[2])
        ... except (ValueError, IndexError) as e:
        ... pass
        ...
        >>>

        4.誤解Python規(guī)則范圍


        Python的作用域解析是基于LEGB規(guī)則,分別是Local、Enclosing、Global、Built-in。實(shí)際上,這種解析方法也有一些玄機(jī),看下面這個例子:


        >>> x = 10
        >>> def foo():
        ... x += 1
        ... print x
        ...
        >>> foo()
        Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "<stdin>", line 2, in foo
        UnboundLocalError: local variable 'x' referenced before assignment

        許多人會感動驚訝,當(dāng)他們在工作的函數(shù)體里添加一個參數(shù)語句,會在先前工作的代碼里報(bào)UnboundLocalError錯誤( 點(diǎn)擊這里查看更詳細(xì)描述)。


        在使用列表時,開發(fā)者是很容易犯這種錯誤的,看看下面這個例子:

        >>> lst = [1, 2, 3]
        >>> def foo1():
        ... lst.append(5) # This works ok...
        ...
        >>> foo1()
        >>> lst
        [1, 2, 3, 5]

        >>> lst = [1, 2, 3]
        >>> def foo2():
        ... lst += [5] # ... but this bombs!
        ...
        >>> foo2()
        Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "<stdin>", line 2, in foo
        UnboundLocalError: local variable 'lst' referenced before assignment

        為什么foo2失敗而foo1運(yùn)行正常?


        答案與前面那個例子是一樣的,但又有一些微妙之處。foo1沒有賦值給lst,而foo2賦值了。lst += [5]實(shí)際上就是lst = lst + [5],試圖給lst賦值(因此,假設(shè)Python是在局部作用域里)。然而,我們正在尋找指定給lst的值是基于lst本身,其實(shí)尚未確定。


        5.修改遍歷列表


        下面這段代碼很明顯是錯誤的:

        >>> odd = lambda x : bool(x % 2)
        >>> numbers = [n for n in range(10)]
        >>> for i in range(len(numbers)):
        ... if odd(numbers[i]):
        ... del numbers[i] # BAD: Deleting item from a list while iterating over it
        ...
        Traceback (most recent call last):
        File "<stdin>", line 2, in <module>
        IndexError: list index out of range

        在遍歷的時候,對列表進(jìn)行刪除操作,這是很低級的錯誤。稍微有點(diǎn)經(jīng)驗(yàn)的人都不會犯。


        對上面的代碼進(jìn)行修改,正確地執(zhí)行:

        >>> odd = lambda x : bool(x % 2)
        >>> numbers = [n for n in range(10)]
        >>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all
        >>> numbers
        [0, 2, 4, 6, 8]

        6.如何在閉包中綁定變量


        看下面這個例子:

        >>> def create_multipliers():
        ... return [lambda x : i * x for i in range(5)]
        >>> for multiplier in create_multipliers():
        ... print multiplier(2)
        ...

        你期望的結(jié)果是:

        <code>0
        2
        4
        6
        8</code>

        實(shí)際上:

        <code>8
        8
        8
        8
        8</code>

        是不是非常吃驚!出現(xiàn)這種情況主要是因?yàn)镻ython的后期綁定行為,該變量在閉包中使用的同時,內(nèi)部函數(shù)又在調(diào)用它。


        解決方案:

        >>> def create_multipliers():
        ... return [lambda x, i=i : i * x for i in range(5)]
        ...
        >>> for multiplier in create_multipliers():
        ... print multiplier(2)
        ...
        0
        2
        4
        6
        8

        7.創(chuàng)建循環(huán)模塊依賴關(guān)系


        假設(shè)有兩個文件,a.py和b.py,然后各自導(dǎo)入,如下:


        在a.py中:

        import b

        def f():
        return b.x

        print f()

        在b.py中:

        import a

        x = 1

        def g():
        print a.f()

        首先,讓我們試著導(dǎo)入a.py:

        <code>>>> import a
        1</code>

        可以很好地工作,也許你會感到驚訝。畢竟,我們確實(shí)在這里做了一個循環(huán)導(dǎo)入,難道不應(yīng)該有點(diǎn)問題嗎?


        僅僅存在一個循環(huán)導(dǎo)入并不是Python本身問題,如果一個模塊被導(dǎo)入,Python就不會試圖重新導(dǎo)入。根據(jù)這一點(diǎn),每個模塊在試圖訪問函數(shù)或變量時,可能會在運(yùn)行時遇到些問題。


        當(dāng)我們試圖導(dǎo)入b.py會發(fā)生什么(先前沒有導(dǎo)入a.py):

        >>> import b
        Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "b.py", line 1, in <module>
        import a
        File "a.py", line 6, in <module>
        print f()
        File "a.py", line 4, in f
        return b.x
        AttributeError: 'module' object has no attribute 'x'

        出錯了,這里的問題是,在導(dǎo)入b.py的過程中還要試圖導(dǎo)入a.py,這樣就要調(diào)用f(),并且試圖訪問b.x。但是b.x并未被定義。


        可以這樣解決,僅僅修改b.py導(dǎo)入到a.py中的g()函數(shù):

        x = 1
        def g():
        import a # This will be evaluated only when g() is called
        print a.f()

        無論何時導(dǎo)入,一切都可以正常運(yùn)行:

        >>> import b
        >>> b.g()
        1 # Printed a first time since module 'a' calls 'print f()' at the end
        1 # Printed a second time, this one is our call to 'g'

        8.與Python標(biāo)準(zhǔn)庫模塊名稱沖突


        Python擁有非常豐富的模塊庫,并且支持“開箱即用”。因此,如果不刻意避免,很容易發(fā)生命名沖突事件。例如,在你的代碼中可能有一個email.py的模塊,由于名稱一致,它很有可能與Python自帶的標(biāo)準(zhǔn)庫模塊發(fā)生沖突。


        9.未按規(guī)定處理Python2.x和Python3.x之間的區(qū)別


        看一下foo.py:

        import sys

        def bar(i):
        if i == 1:
        raise KeyError(1)
        if i == 2:
        raise ValueError(2)

        def bad():
        e = None
        try:
        bar(int(sys.argv[1]))
        except KeyError as e:
        print('key error')
        except ValueError as e:
        print('value error')
        print(e)

        bad()

        在Python 2里面可以很好地運(yùn)行:

        $ python foo.py 1
        key error
        1
        $ python foo.py 2
        value error
        2

        但是在Python 3里:

        $ python3 foo.py 1
        key error
        Traceback (most recent call last):
        File "foo.py", line 19, in <module>
        bad()
        File "foo.py", line 17, in bad
        print(e)
        UnboundLocalError: local variable 'e' referenced before assignment

        解決方案:

        import sys

        def bar(i):
        if i == 1:
        raise KeyError(1)
        if i == 2:
        raise ValueError(2)

        def good():
        exception = None
        try:
        bar(int(sys.argv[1]))
        except KeyError as e:
        exception = e
        print('key error')
        except ValueError as e:
        exception = e
        print('value error')
        print(exception)

        good()

        在Py3k中運(yùn)行結(jié)果:

        <code>$ python3 foo.py 1
        key error
        1
        $ python3 foo.py 2
        value error
        2</code>

        在 Python招聘指南里有許多關(guān)于Python 2與Python 3在移植代碼時需要關(guān)注的注意事項(xiàng)與討論,大家可以前往看看。


        10.濫用__del__方法


        比如這里有一個叫mod.py的文件:

        import foo
        class Bar(object):
        ...
        def __del__(self):
        foo.cleanup(self.myhandle)

        下面,你在another_mod.py文件里執(zhí)行如下操作:

        import mod
        mybar = mod.Bar()

        你會獲得一個AttributeError異常。


        至于為什么會出現(xiàn)該異常,點(diǎn)擊這里查看詳情。當(dāng)解釋器關(guān)閉時,該模塊的全局變量全部設(shè)置為None。因此,在上面這個例子里,當(dāng)__del__被調(diào)用時,foo已經(jīng)全部被設(shè)置為None。


        一個很好的解決辦法是使用atexit.register()代替。順便說一句,當(dāng)程序執(zhí)行完成后,您注冊的處理程序會在解釋器關(guān)閉之前停止 工作。


        修復(fù)上面問題的代碼:

        import foo
        import atexit

        def cleanup(handle):
        foo.cleanup(handle)


        class Bar(object):
        def __init__(self):
        ...
        atexit.register(cleanup, self.myhandle)

        在程序的正常終止的前提下,這個實(shí)現(xiàn)提供了一個整潔可靠的方式調(diào)用任何需要清理的功能。


        總結(jié)


        Python是一款強(qiáng)大而靈活的編程語言,并且?guī)в性S多機(jī)制和模式來大大提高工作效率。正如任何一門語言或軟件工具一樣,人們對其能力都會存在一個限制性地理解或欣賞,有些是弊大于利,有些時候反而會帶來一些陷進(jìn)。體會一名語言的細(xì)微之處,理解一些常見的陷阱,有助于你在開發(fā)者的道路上走的更遠(yuǎn)。


        來自:toptal,CSDN編譯

        鏈接:https://www.csdn.net/article/2014-05-12/2819716-Top-10-Mistakes-that-Python-Programmers-Make




        1. YYDS!一行Python代碼即可實(shí)現(xiàn)數(shù)據(jù)可視化大屏

        2. 計(jì)算機(jī)專業(yè)會不會成為下一個土木?

        3. 為什么國內(nèi)做不出 JetBrains 那樣的產(chǎn)品?



        瀏覽 79
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            成人免费毛片在线观看 | 真人老太婆一级A片免费 | 色天堂污 | 日本乱伦中文字幕 | 欧洲精品一区二区三区 | 天天透天天插 | 地铁上的调教高h | 亚洲AA视频 | 欧美成人高清在线 | 国产黄色电影在线观看 |