搜尋

首頁  >  問答  >  主體

关于python 默认参数的疑问

python文档中关于默认参数是这样说的:

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call.

因此,如下代码:

def function(data=[]):
    print id(data), data
    data.append(1)

for i in range(3):
    function()

输出结果为:

4462873272 []
4462873272 [1]
4462873272 [1, 1]

一切正像文档中说的那样,data只计算一次,之后的调用返回的是已经计算出来的值(因此,id(data)没有变化,每次append均针对同一个data)

但是我们带参数调用function时,即:

for i in range(3):
    function([])

输出结果为:

4462872984 []
4462872984 []
4462872984 []

data的值是符合预期的,但是三次调用function,id(data)的值竟然也一样,这个是为什么呢?带参数传递时,每次调用都应该是新建data的吧。

PHP中文网PHP中文网2805 天前895

全部回覆(5)我來回復

  • PHP中文网

    PHP中文网2017-04-17 13:39:41

    認真唸文件啊:https://docs.python.org/2/library/functions.html#id 。
    Because:

    Two objects with non-overlapping lifetimes may have the same id() value.

    CPython中id的實作概念上相當於物件在記憶體中的位址。那請看這段程式碼:

    id([])
    # then it destory
    id([])
    # then its memory reused
    

    前後是兩個不同的list對象,但既然前面一個對像用完就被銷毀掉了,那後面的一個list就可能重用相同的內存空間,所以id返回的地址就是一樣的了。

    回覆
    0
  • 天蓬老师

    天蓬老师2017-04-17 13:39:41

    LZ請注意常數與變數的區別, 你想要個不同的id, 得用list()。

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-17 13:39:41

    雖然不明白最後到底有沒有回答到問題深處, 但如果這個答案能幫助有的同學對參數的疑惑 也是好的.

    前一陣子我也是剛學python, 看到關於預設參數列表的一部分, 說一下我的理解.

    當呼叫函數f() 連續三次時,

    第一次 f() 會找到預設參數 data = []
    而且它在記憶體中的位址是能通過 類似 'f.data' 尋址的.
    接下來再次呼叫 f() 會重複以上操作, 因為沒有輸入一個新的參數, 會預設還是找到先前的data作為此次參數列表.

    def f(data = []):
        data.append("end")
        print data
    

    f()

    執行前 data = []
    執行後 預設參數變成 data =['end']

    f()

    重複上次操作 這裡data 可以理解為該函數的一個成員變數


    另外 也可以呼叫 f.defaults 這個屬性來查看函數f當前情況的預設參數是什麼

    如 定義完f後,

     # 定义完f后的默认参数
    print f.__defaults__
    #>>([],)
    # f() 执行后的默认参数
    print f.__defaults__
    #>>(['end'],)
    

    所以預設參數在前後幾次 f()執行過程中是可變的.

    而如果呼叫f([]) 的話 是不會對預設參數產生影響的,

    print f.__defaults__
    f([])
    print f.__defaults__
    f([])
    print f.__defaults__
    

    如果有興趣還可以試試看 對
    f(data = [] ) 進行迭代 :)

    可以參考這裡 覺得講的很清楚 Python 函數的參數

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-17 13:39:41

    這個問題是這樣子的...
    這是算是python比較高級的內容了吧..初學者基本上都會碰到這個問題


    好了,正文開始

    函數的內省導致了,你的參數是函數類型的一個屬性(雖然沒辦法用.來訪問).
    這也就是意味著,你在定義函數的時候,你的參數已經成了這個函數對象的一部分了..類似於:

    class cls():
        A = []
    
    a = cls()
    b = cls()
    a.A.append("a")
    print b.A
    

    你可以發現有剛剛的"a"被印出來了..
    函數這邊也是一樣的.定義的參數屬性是共享的
    但是以上規則僅針對於可變資料型別,例如清單
    因為不可變資料型別不是在目前這個記憶體區塊裡面修改的...而是指向了另外一個記憶體區塊..


    延伸閱讀:

    兩個python特性:

    1. python的動態型別問題:

    動態類型的意思是:你的變數只是一個類似指標的東西.只不過他可以隨便亂指...他指向的是一個型別.這個類型可以是整數,字串,類別等等.

    你的一個變數可以更換指向的類型.例如:a = 1a指向的是一個整數類型.這個整數類型的值是1(當然還有其他一些組成部分,例如還有count和類型聲明等等)
    但是當你從新指向的時候,比如:a = "hello world",那麼發生的事情是,a這個變數指向了一個字串類型,而之前1這個整型發生的變化是count-1,等count為0了記憶體才被回收.
    這就是傳說中的動態型

    2. 函數的內省

    函數在python中也是型態.
    例如你

    def foo(a, b):
        pass
    

    那麼就是產生了一個函數型別,賦值給foo這個變數了..
    而這個型別中所有東西都可以透過域運算子 . 來操作.


    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 13:39:41

    同意ls

    回覆
    0
  • 取消回覆