最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入討論Python函數(shù)的參數(shù)的默認值所引發(fā)的問題的原因

 更新時間:2015年03月30日 10:33:27   作者:盧鈞軼  
這篇文章主要介紹了深入討論Python函數(shù)的參數(shù)的默認值所引發(fā)的問題的原因,利用了Python解釋器在內(nèi)存地址分配中的過程解釋了參數(shù)默認值帶來陷阱的原因,需要的朋友可以參考下

本文將介紹使用mutable對象作為Python函數(shù)參數(shù)默認值潛在的危害,以及其實現(xiàn)原理和設(shè)計目的
陷阱重現(xiàn)

我們就用實際的舉例來演示我們今天所要討論的主要內(nèi)容。

下面一段代碼定義了一個名為 generate_new_list_with 的函數(shù)。該函數(shù)的本意是在每次調(diào)用時都新建一個包含有給定 element 值的list。而實際運行結(jié)果如下:
 

Python 2.7.9 (default, Dec 19 2014, 06:05:48)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def generate_new_list_with(my_list=[], element=None):
...   my_list.append(element)
...   return my_list
...
>>> list_1 = generate_new_list_with(element=1)
>>> list_1
[1]
>>> list_2 = generate_new_list_with(element=2)
>>> list_2
[1, 2]
>>>

可見代碼運行結(jié)果并不和我們預(yù)期的一樣。list_2在函數(shù)的第二次調(diào)用時并沒有得到一個新的list并填入2,而是在第一次調(diào)用結(jié)果的基礎(chǔ)上append了一個2。為什么會發(fā)生這樣在其他編程語言中簡直就是設(shè)計bug一樣的問題呢?
準備知識:Python變量的實質(zhì)

要了解這個問題的原因我們先需要一個準備知識,那就是:Python變量到底是如何實現(xiàn)的?

Python變量區(qū)別于其他編程語言的申明&賦值方式,采用的是創(chuàng)建&指向的類似于指針的方式實現(xiàn)的。即Python中的變量實際上是對值或者對象的一個指針(簡單的說他們是值得一個名字)。我們來看一個例子。
 

p = 1
p = p+1

對于傳統(tǒng)語言,上面這段代碼的執(zhí)行方式將會是,先在內(nèi)存中申明一個p的變量,然后將1存入變量p所在內(nèi)存。執(zhí)行加法操作的時候得到2的結(jié)果,將2這個數(shù)值再次存入到p所在內(nèi)存地址中??梢娬麄€執(zhí)行過程中,變化的是變量p所在內(nèi)存地址上的值

面這段代碼中,Python實際上是現(xiàn)在執(zhí)行內(nèi)存中創(chuàng)建了一個1的對象,并將p指向了它。在執(zhí)行加法操作的時候,實際上通過加法操作得到了一個2的新對象,并將p指向這個新的對象??梢娬麄€執(zhí)行過程中,變化的是p指向的內(nèi)存地址
函數(shù)參數(shù)默認值陷阱的根本原因

一句話來解釋:Python函數(shù)的參數(shù)默認值,是在編譯階段就綁定的。

現(xiàn)在,我們先從一段摘錄來詳細分析這個陷阱的原因。下面是一段從Python Common Gotchas中摘錄的原因解釋:

Python's default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.

可見如果參數(shù)默認值是在函數(shù)編譯compile階段就已經(jīng)被確定。之后所有的函數(shù)調(diào)用時,如果參數(shù)不顯示的給予賦值,那么所謂的參數(shù)默認值不過是一個指向那個在compile階段就已經(jīng)存在的對象的指針。如果調(diào)用函數(shù)時,沒有顯示指定傳入?yún)?shù)值得話。那么所有這種情況下的該參數(shù)都會作為編譯時創(chuàng)建的那個對象的一種別名存在。

如果參數(shù)的默認值是一個不可變(Imuttable)數(shù)值,那么在函數(shù)體內(nèi)如果修改了該參數(shù),那么參數(shù)就會重新指向另一個新的不可變值。而如果參數(shù)默認值是和本文最開始的舉例一樣,是一個可變對象(Muttable),那么情況就比較糟糕了。所有函數(shù)體內(nèi)對于該參數(shù)的修改,實際上都是對compile階段就已經(jīng)確定的那個對象的修改。

對于這么一個陷阱在 Python官方文檔中也有特別提示:

Important warning: The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes. For example, the following function accumulates the arguments passed to it on subsequent calls:
如何避免這個陷阱帶來不必要麻煩

當然最好的方式是不要使用可變對象作為函數(shù)默認值。如果非要這么用的話,下面是一種解決方案。還是以文章開頭的需求為例:
 

def generate_new_list_with(my_list=None, element=None):
  if my_list is None:
    my_list = []
  my_list.append(element)
  return my_list

為什么Python要這么設(shè)計

這個問題的答案在StackOverflow 上可以找到答案。這里將得票數(shù)最多的答案最重要的部分摘錄如下:

Actually, this is not a design flaw, and it is not because of internals, or performance.

It comes simply from the fact that functions in Python are first-class objects, and not only a piece of code.

As soon as you get to think into this way, then it completely makes sense: a function is an object being evaluated on its definition; default parameters are kind of “member data” and therefore their state may change from one call to the other – exactly as in any other object.

In any case, Effbot has a very nice explanation of the reasons for this behavior in Default Parameter Values in Python.

I found it very clear, and I really suggest reading it for a better knowledge of how function objects work.

在這個回答中,答題者認為出于Python編譯器的實現(xiàn)方式考慮,函數(shù)是一個內(nèi)部一級對象。而參數(shù)默認值是這個對象的屬性。在其他任何語言中,對象屬性都是在對象創(chuàng)建時做綁定的。因此,函數(shù)參數(shù)默認值在編譯時綁定也就不足為奇了。
然而,也有其他很多一些回答者不買賬,認為即使是first-class object也可以使用closure的方式在執(zhí)行時綁定。

This is not a design flaw. It is a design decision; perhaps a bad one, but not an accident. The state thing is just like any other closure: a closure is not a function, and a function with mutable default argument is not a function.

甚至還有反駁者拋開實現(xiàn)邏輯,單純從設(shè)計角度認為:只要是違背程序猿基本思考邏輯的行為,都是設(shè)計缺陷!下面是他們的一些論調(diào):

> Sorry, but anything considered “The biggest WTF in Python” is most definitely a design flaw. This is a source of bugs for everyone at some point, because no one expects that behavior at first – which means it should not have been designed that way to begin with.

The phrases “this is not generally what was intended” and “a way around this is” smell like they're documenting a design flaw.

好吧,這么看來,如果沒有來自于Python作者的親自陳清,這個問題的答案就一直會是一個謎了。

相關(guān)文章

  • Python基于staticmethod裝飾器標示靜態(tài)方法

    Python基于staticmethod裝飾器標示靜態(tài)方法

    這篇文章主要介紹了Python基于staticmethod裝飾器標示靜態(tài)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10
  • python中字典增加和刪除使用方法

    python中字典增加和刪除使用方法

    這篇文章主要介紹了python中字典增加和刪除使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • Python使用HTTP POST上傳WAV文件的方法

    Python使用HTTP POST上傳WAV文件的方法

    Python是一個非常流行的編程語言,可以用于開發(fā)不同類型的應(yīng)用程序。其中,上傳文件是一個非常常見的需求。具體而言,我們探討了使用HTTP POST請求上傳單個和多個WAV文件的方法。無論你是需要將音頻文件上傳到云存儲還是服務(wù)器,這些方法都能幫助你上傳文件。
    2023-06-06
  • PyCharm進行Django項目開發(fā)環(huán)境搭建

    PyCharm進行Django項目開發(fā)環(huán)境搭建

    本文主要介紹了PyCharm進行Django項目開發(fā)環(huán)境搭建,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-02-02
  • Python asyncio異步編程簡單實現(xiàn)示例

    Python asyncio異步編程簡單實現(xiàn)示例

    本文主要介紹了Python asyncio異步編程簡單實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • Python tkinter實現(xiàn)簡單加法計算器代碼實例

    Python tkinter實現(xiàn)簡單加法計算器代碼實例

    這篇文章主要介紹了Python tkinter實現(xiàn)簡單加法計算器代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • Pycharm連接遠程服務(wù)器過程圖解

    Pycharm連接遠程服務(wù)器過程圖解

    這篇文章主要介紹了Pycharm連接遠程服務(wù)器過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • Python爬取OPGG上英雄聯(lián)盟英雄勝率及選取率信息的操作

    Python爬取OPGG上英雄聯(lián)盟英雄勝率及選取率信息的操作

    這篇文章主要介紹了Python爬取OPGG上英雄聯(lián)盟英雄勝率及選取率信息的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Python基礎(chǔ)語法(Python基礎(chǔ)知識點)

    Python基礎(chǔ)語法(Python基礎(chǔ)知識點)

    這篇文章主要介紹了Python基礎(chǔ)語法(Python基礎(chǔ)知識點),需要的朋友可以參考下
    2016-02-02
  • python 獲取字典鍵值對的實現(xiàn)

    python 獲取字典鍵值對的實現(xiàn)

    這篇文章主要介紹了python 獲取字典鍵值對的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11

最新評論

乐业县| 临潭县| 贡觉县| 蓬溪县| 刚察县| 界首市| 县级市| 灵寿县| 南开区| 栾城县| 胶南市| 郸城县| 界首市| 东丰县| 德惠市| 天祝| 丹阳市| 沅陵县| 永兴县| 拉萨市| 榆中县| 奉节县| 邵阳县| 全南县| 舒城县| 乌海市| 若羌县| 万宁市| 辽源市| 西昌市| 武平县| 寿阳县| 晋宁县| 西峡县| 崇礼县| 宾阳县| 伊金霍洛旗| 建平县| 赤水市| 麻阳| 浦城县|