第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

“最小的驚訝”和可變的默認(rèn)論證-python

“最小的驚訝”和可變的默認(rèn)論證-python

炎炎設(shè)計(jì) 2019-05-20 16:06:05
任何修補(bǔ)Python足夠長的人都被以下問題咬傷(或撕成碎片):def foo(a=[]):    a.append(5)    return aPython新手希望這個(gè)函數(shù)總能返回一個(gè)只包含一個(gè)元素的列表:[5]。結(jié)果卻非常不同,而且非常驚人(對于新手來說):>>> foo()[5]>>> foo()[5, 5]>>> foo()[5, 5, 5]>>> foo()[5, 5, 5, 5]>>> foo()我的一位經(jīng)理曾經(jīng)第一次遇到這個(gè)功能,并稱其為該語言的“戲劇性設(shè)計(jì)缺陷”。我回答說這個(gè)行為有一個(gè)潛在的解釋,如果你不理解內(nèi)部,那確實(shí)非常令人費(fèi)解和意想不到。但是,我無法回答(對自己)以下問題:在函數(shù)定義中綁定默認(rèn)參數(shù)的原因是什么,而不是在函數(shù)執(zhí)行時(shí)?我懷疑經(jīng)驗(yàn)豐富的行為有實(shí)際用途(誰真的在C中使用靜態(tài)變量,沒有繁殖錯(cuò)誤?)編輯:巴澤克提出了一個(gè)有趣的例子。再加上你的大部分評論和特別是Utaal,我進(jìn)一步闡述了:>>> def a():...     print("a executed")...     return []... >>>            >>> def b(x=a()):...     x.append(5)...     print(x)... a executed>>> b()[5]>>> b()[5, 5]對我而言,似乎設(shè)計(jì)決策是相對于放置參數(shù)范圍的位置:在函數(shù)內(nèi)部還是“與它一起”?在函數(shù)內(nèi)部進(jìn)行綁定意味著在調(diào)用函數(shù)時(shí)x有效地綁定到指定的默認(rèn)值,而不是定義,這會(huì)產(chǎn)生一個(gè)深層次的缺陷:該def行在某種意義上是“混合”的(部分綁定)函數(shù)對象)將在定義時(shí)發(fā)生,并在函數(shù)調(diào)用時(shí)發(fā)生部分(默認(rèn)參數(shù)的賦值)。實(shí)際行為更加一致:執(zhí)行該行時(shí),該行的所有內(nèi)容都會(huì)得到評估,這意味著在函數(shù)定義中。
查看完整描述

6 回答

?
侃侃爾雅

TA貢獻(xiàn)1801條經(jīng)驗(yàn) 獲得超16個(gè)贊

實(shí)際上,這不是設(shè)計(jì)缺陷,并不是因?yàn)閮?nèi)部或性能。
它只是因?yàn)镻ython中的函數(shù)是第一類對象,而不僅僅是一段代碼。

一旦你以這種方式思考,那么它就完全有意義了:一個(gè)函數(shù)是一個(gè)被定義的對象; 默認(rèn)參數(shù)是一種“成員數(shù)據(jù)”,因此它們的狀態(tài)可能會(huì)從一個(gè)調(diào)用更改為另一個(gè)調(diào)用 - 與任何其他對象完全相同。

無論如何,Effbot 對Python中的默認(rèn)參數(shù)值中出現(xiàn)這種行為的原因有一個(gè)非常好的解釋。
我發(fā)現(xiàn)它非常清楚,我真的建議閱讀它以更好地了解函數(shù)對象的工作原理。


查看完整回答
反對 回復(fù) 2019-05-20
?
慕沐林林

TA貢獻(xiàn)2016條經(jīng)驗(yàn) 獲得超9個(gè)贊

假設(shè)您有以下代碼


fruits = ("apples", "bananas", "loganberries")


def eat(food=fruits):

    ...

當(dāng)我看到吃的聲明時(shí),最令人驚訝的是認(rèn)為如果沒有給出第一個(gè)參數(shù),它將等于元組 ("apples", "bananas", "loganberries")


但是,假設(shè)后面的代碼,我會(huì)做類似的事情


def some_random_function():

    global fruits

    fruits = ("blueberries", "mangos")

然后,如果默認(rèn)參數(shù)在函數(shù)執(zhí)行而不是函數(shù)聲明中被綁定,那么我會(huì)驚訝地發(fā)現(xiàn)水果已被改變(以非常糟糕的方式)。這比發(fā)現(xiàn)foo上面的函數(shù)改變列表更令人驚訝的IMO 。


真正的問題在于可變變量,并且所有語言在某種程度上都存在這個(gè)問題。這是一個(gè)問題:假設(shè)在Java中我有以下代碼:


StringBuffer s = new StringBuffer("Hello World!");

Map<StringBuffer,Integer> counts = new HashMap<StringBuffer,Integer>();

counts.put(s, 5);

s.append("!!!!");

System.out.println( counts.get(s) );  // does this work?

現(xiàn)在,我的地圖StringBuffer在放入地圖時(shí)是否使用了鍵的值,還是通過引用存儲(chǔ)了鍵?無論哪種方式,有人感到驚訝; 嘗試將對象從Map使用中取出的值與他們放入的對象相同的人,或者即使他們使用的鍵實(shí)際上是同一個(gè)對象而無法檢索其對象的人用于將其放入映射的(這實(shí)際上是Python不允許其可變內(nèi)置數(shù)據(jù)類型用作字典鍵的原因)。


你的例子是一個(gè)很好的例子,Python新人會(huì)感到驚訝和被咬。但我認(rèn)為,如果我們“修復(fù)”這個(gè),那么這只會(huì)產(chǎn)生一種不同的情況,即他們會(huì)被咬傷,而那種情況甚至?xí)恢庇^。而且,在處理可變變量時(shí)總是如此; 你總是遇到一些情況,根據(jù)他們正在編寫的代碼,某人可能直觀地期望一種或相反的行為。


我個(gè)人喜歡Python當(dāng)前的方法:默認(rèn)函數(shù)參數(shù)在定義函數(shù)時(shí)進(jìn)行評估,并且該對象始終是默認(rèn)值。我想他們可以使用空列表進(jìn)行特殊情況,但這種特殊的外殼會(huì)引起更多的驚訝,更不用說倒退不兼容了


查看完整回答
反對 回復(fù) 2019-05-20
?
楊魅力

TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超6個(gè)贊

AFAICS尚未發(fā)布文檔的相關(guān)部分:

執(zhí)行函數(shù)定義時(shí),將評估默認(rèn)參數(shù)值。這意味著當(dāng)定義函數(shù)時(shí),表達(dá)式被計(jì)算一次,并且每次調(diào)用使用相同的“預(yù)先計(jì)算”值。這對于理解默認(rèn)參數(shù)是可變對象(例如列表或字典)時(shí)尤其重要:如果函數(shù)修改對象(例如,通過將項(xiàng)附加到列表),則默認(rèn)值實(shí)際上被修改。這通常不是預(yù)期的。解決這個(gè)問題的方法是使用None作為默認(rèn)值,并在函數(shù)體中顯式測試它[...]


查看完整回答
反對 回復(fù) 2019-05-20
?
尚方寶劍之說

TA貢獻(xiàn)1788條經(jīng)驗(yàn) 獲得超4個(gè)贊

我對Python解釋器內(nèi)部工作一無所知(我也不是編譯器和解釋器方面的專家)所以如果我提出任何不可知或不可能的建議,請不要責(zé)怪我。

如果python對象是可變的,我認(rèn)為在設(shè)計(jì)默認(rèn)參數(shù)時(shí)應(yīng)該考慮到這一點(diǎn)。實(shí)例化列表時(shí):

a = []

你希望得到一個(gè)新的列表引用a

為什么要a=[]進(jìn)去

def x(a=[]):

在函數(shù)定義上實(shí)例化一個(gè)新列表而不是在調(diào)用上?就像你問“用戶是否提供參數(shù)然后實(shí)例化一個(gè)新列表并使用它就好像它是由調(diào)用者生成”一樣。我認(rèn)為這是模棱兩可的:

def x(a=datetime.datetime.now()):

用戶,是否要a默認(rèn)為與定義或執(zhí)行時(shí)相對應(yīng)的日期時(shí)間x?在這種情況下,與前一個(gè)一樣,我將保持相同的行為,就好像默認(rèn)參數(shù)“assignment”是函數(shù)的第一條指令(datetime.now()在函數(shù)調(diào)用上調(diào)用)。另一方面,如果用戶想要定義時(shí)間映射,他可以寫:

b = datetime.datetime.now()def x(a=b):

我知道,我知道:這是一個(gè)封閉?;蛘撸琍ython可能會(huì)提供一個(gè)關(guān)鍵字來強(qiáng)制定義時(shí)綁定:

def x(static a=b):


查看完整回答
反對 回復(fù) 2019-05-20
?
隔江千里

TA貢獻(xiàn)1906條經(jīng)驗(yàn) 獲得超10個(gè)贊

嗯,原因很簡單,在執(zhí)行代碼時(shí)完成綁定,并且執(zhí)行函數(shù)定義,以及......定義函數(shù)時(shí)。

比較一下:

class BananaBunch:
    bananas = []

    def addBanana(self, banana):
        self.bananas.append(banana)

此代碼遭受完全相同的意外事件。bananas是一個(gè)類屬性,因此,當(dāng)您向其添加內(nèi)容時(shí),它會(huì)添加到該類的所有實(shí)例中。原因完全一樣。

這只是“如何工作”,并且在功能案例中使其工作方式可能很復(fù)雜,并且在類的情況下可能不可能,或者至少減慢對象實(shí)例化的速度,因?yàn)槟惚仨毐3诸惔a并在創(chuàng)建對象時(shí)執(zhí)行它。

是的,這是出乎意料的。但是一旦下降了,它就完全適合Python的工作方式。事實(shí)上,它是一個(gè)很好的教學(xué)輔助工具,一旦你理解了為什么會(huì)這樣,你就會(huì)更好地理解python。

這說它應(yīng)該在任何優(yōu)秀的Python教程中占據(jù)突出地位。因?yàn)檎缒闼岬降模總€(gè)人遲早都會(huì)遇到這個(gè)問題。


查看完整回答
反對 回復(fù) 2019-05-20
?
繁星coding

TA貢獻(xiàn)1797條經(jīng)驗(yàn) 獲得超4個(gè)贊

我曾經(jīng)認(rèn)為在運(yùn)行時(shí)創(chuàng)建對象將是更好的方法。我現(xiàn)在不太確定,因?yàn)槟愦_實(shí)失去了一些有用的功能,盡管它可能是值得的,不管只是為了防止新手混淆。這樣做的缺點(diǎn)是:


1.表現(xiàn)


def foo(arg=something_expensive_to_compute())):

    ...

如果使用了調(diào)用時(shí)評估,則每次使用函數(shù)時(shí)都會(huì)調(diào)用昂貴的函數(shù)而不使用參數(shù)。您要么為每次調(diào)用付出昂貴的代價(jià),要么需要在外部手動(dòng)緩存該值,污染您的命名空間并添加詳細(xì)程度。


2.強(qiáng)制綁定參數(shù)


一個(gè)有用的技巧是在創(chuàng)建lambda時(shí)將lambda的參數(shù)綁定到變量的當(dāng)前綁定。例如:


funcs = [ lambda i=i: i for i in range(10)]

這將返回分別返回0,1,2,3 ...的函數(shù)列表。如果行為發(fā)生了變化,它們將綁定i到i 的調(diào)用時(shí)間值,因此您將獲得所有返回的函數(shù)列表9。


否則實(shí)現(xiàn)此方法的唯一方法是使用i綁定創(chuàng)建進(jìn)一步的閉包,即:


def make_func(i): return lambda: i

funcs = [make_func(i) for i in range(10)]

3.內(nèi)省


考慮一下代碼:


def foo(a='test', b=100, c=[]):

   print a,b,c

我們可以使用inspect模塊獲取有關(guān)參數(shù)和默認(rèn)值的信息


>>> inspect.getargspec(foo)

(['a', 'b', 'c'], None, None, ('test', 100, []))

這些信息對于文檔生成,元編程,裝飾器等非常有用。


現(xiàn)在,假設(shè)可以更改默認(rèn)值的行為,以便這相當(dāng)于:


_undefined = object()  # sentinel value


def foo(a=_undefined, b=_undefined, c=_undefined)

    if a is _undefined: a='test'

    if b is _undefined: b=100

    if c is _undefined: c=[]

但是,我們已經(jīng)失去了內(nèi)省的能力,并且看到了默認(rèn)參數(shù)是什么。因?yàn)闆]有構(gòu)造對象,所以我們不能在沒有實(shí)際調(diào)用函數(shù)的情況下獲取它們。我們能做的最好的事情是存儲(chǔ)源代碼并將其作為字符串返回。


查看完整回答
反對 回復(fù) 2019-05-20
  • 6 回答
  • 0 關(guān)注
  • 529 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號