午夜国产狂喷潮在线观看|国产AⅤ精品一区二区久久|中文字幕AV中文字幕|国产看片高清在线

    Python程序員開(kāi)發(fā)中常犯的10個(gè)錯(cuò)誤
    來(lái)源:易賢網(wǎng) 閱讀:1002 次 日期:2014-07-08 18:58:15
    溫馨提示:易賢網(wǎng)小編為您整理了“Python程序員開(kāi)發(fā)中常犯的10個(gè)錯(cuò)誤”,方便廣大網(wǎng)友查閱!

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

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

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

    Python允許開(kāi)發(fā)者指定一個(gè)默認(rèn)值給函數(shù)參數(shù),雖然這是該語(yǔ)言的一個(gè)特征,但當(dāng)參數(shù)可變時(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ù)(沒(méi)有指定一個(gè)bar參數(shù)),那么將一直返回'bar',因?yàn)闆](méi)有指定參數(shù),那么foo()每次被調(diào)用的時(shí)候,都會(huì)賦予[]。下面來(lái)看看,這樣做的結(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.錯(cuò)誤地使用類(lèi)變量

    先看下面這個(gè)例子:

    代碼如下:

    >>> 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

    再來(lái)一遍:

    代碼如下:

    >>> A.x = 3

    >>> print A.x, B.x, C.x

    3 2 3

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

    在Python中,類(lèi)變量都是作為字典進(jìn)行內(nèi)部處理的,并且遵循方法解析順序(MRO)。在上面這段代碼中,因?yàn)閷傩詘沒(méi)有在類(lèi)C中發(fā)現(xiàn),它會(huì)查找它的基類(lèi)(在上面例子中只有A,盡管Python支持多繼承)。換句話(huà)說(shuō),就是C自己沒(méi)有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

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

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

    代碼如下:

    >>> 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ī),看下面這個(gè)例子:

    代碼如下:

    >>> 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

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

    在使用列表時(shí),開(kāi)發(fā)者是很容易犯這種錯(cuò)誤的,看看下面這個(gè)例子:

    代碼如下:

    >>> 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)行正常?

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

    5.修改遍歷列表

    下面這段代碼很明顯是錯(cuò)誤的:

    代碼如下:

    >>> 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

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

    對(duì)上面的代碼進(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.如何在閉包中綁定變量

    看下面這個(gè)例子:

    代碼如下:

    >>> def create_multipliers():

    ...     return [lambda x : i * x for i in range(5)]

    >>> for multiplier in create_multipliers():

    ...     print multiplier(2)

    ...

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

    代碼如下:

    0

    2

    4

    6

    8

    實(shí)際上:

    代碼如下:

    8

    8

    8

    8

    8

    是不是非常吃驚!出現(xiàn)這種情況主要是因?yàn)镻ython的后期綁定行為,該變量在閉包中使用的同時(shí),內(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)模塊依賴(lài)關(guān)系

    假設(shè)有兩個(gè)文件,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()

    首先,讓我們?cè)囍鴮?dǎo)入a.py:

    代碼如下:>>> import a

    1

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

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

    當(dāng)我們?cè)噲D導(dǎo)入b.py會(huì)發(fā)生什么(先前沒(méi)有導(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'

    出錯(cuò)了,這里的問(wèn)題是,在導(dǎo)入b.py的過(guò)程中還要試圖導(dǎo)入a.py,這樣就要調(diào)用f(),并且試圖訪(fǎng)問(wèn)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()

    無(wú)論何時(shí)導(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)庫(kù)模塊名稱(chēng)沖突

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

    代碼如下:$ python3 foo.py 1

    key error

    1

    $ python3 foo.py 2

    value error

    2

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

    10.濫用__del__方法

    比如這里有一個(gè)叫mod.py的文件:

    代碼如下:

    import foo

    class Bar(object):

            ...

        def __del__(self):

            foo.cleanup(self.myhandle)

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

    代碼如下:

    import mod

    mybar = mod.Bar()

    你會(huì)獲得一個(gè)AttributeError異常。

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

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

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

    代碼如下:

    import foo

    import atexit

    def cleanup(handle):

        foo.cleanup(handle)

    class Bar(object):

        def __init__(self):

            ...

            atexit.register(cleanup, self.myhandle)

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

    總結(jié)

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

    更多信息請(qǐng)查看IT技術(shù)專(zhuān)欄

    更多信息請(qǐng)查看腳本欄目
    易賢網(wǎng)手機(jī)網(wǎng)站地址:Python程序員開(kāi)發(fā)中常犯的10個(gè)錯(cuò)誤
    由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢(xún)回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門(mén)公布的正式信息和咨詢(xún)?yōu)闇?zhǔn)!

    2025國(guó)考·省考課程試聽(tīng)報(bào)名

    • 報(bào)班類(lèi)型
    • 姓名
    • 手機(jī)號(hào)
    • 驗(yàn)證碼
    關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢(xún) | 簡(jiǎn)要咨詢(xún)須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
    工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
    云南網(wǎng)警備案專(zhuān)用圖標(biāo)
    聯(lián)系電話(huà):0871-65099533/13759567129 獲取招聘考試信息及咨詢(xún)關(guān)注公眾號(hào):hfpxwx
    咨詢(xún)QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
    云南網(wǎng)警報(bào)警專(zhuān)用圖標(biāo)