关于python 默认参数的疑问
PHP中文网
PHP中文网 2017-04-17 13:37:41
0
5
884

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中文网

认证0级讲师

全部回覆(5)
Ty80

認真唸文件啊: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返回的地址就是一樣的了。

Peter_Zhu

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

巴扎黑

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

前一陣子我也是剛學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 函數的參數

左手右手慢动作

這個問題是這樣子的...
這是算是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這個變數了..
而這個型別中所有東西都可以透過域運算子 . 來操作.


伊谢尔伦

同意ls

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板