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

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

Python 的新“functools.cached_property”錯(cuò)誤或限制?

Python 的新“functools.cached_property”錯(cuò)誤或限制?

搖曳的薔薇 2022-12-20 12:24:41
從 Python 3.8 開(kāi)始,functools有一個(gè)cached_property. 我一直在使用lazyprop基于 Beazley 的食譜(下面的代碼)的類(lèi)似裝飾器,但是當(dāng)我用內(nèi)置函數(shù)替換時(shí),我遇到了問(wèn)題。這是其中之一。當(dāng)我在類(lèi)定義中使用裝飾器時(shí),使用@運(yùn)算符,它不會(huì)抱怨。但是,如果我將它與 一起使用setattr,我會(huì)得到:TypeError: Cannot use cached_property instance without calling __set_name__ on it.Beazley 的簡(jiǎn)單版本雖然工作正常。from functools import cached_propertyclass lazyprop:    """Based on code from David Beazley's "Python Cookbook"."""    def __init__(self, func):        self.__doc__ = getattr(func, '__doc__')        self.func = func    def __get__(self, instance, cls):        if instance is None:            return self        else:            value = instance.__dict__[self.func.__name__] = self.func(instance)            return valueclass D:    def __init__(self, greeting='Hello'):        self.greeting = greetingdef greet(self):    return self.greeting + " world!"# Beazley's version works...D.greet = lazyprop(greet)assert D().greet == "Hello world!"# ... but the builtin version will failD.greet = cached_property(greet)# D().greet  # this will fail
查看完整描述

2 回答

?
元芳怎么了

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

緩存是實(shí)例字典本身,并且需要屬性的名稱(chēng)作為鍵。所選設(shè)計(jì)施加了限制,但(IMO)這是一個(gè)很好的折衷方案。lazyprop不是線(xiàn)程安全的,或者至少self.func在多線(xiàn)程環(huán)境中調(diào)用的次數(shù)可能超過(guò)絕對(duì)必要的次數(shù)。


首先,它被記錄__set_name__在只有在賦值發(fā)生在類(lèi)型創(chuàng)建的上下文中時(shí)才會(huì)被調(diào)用。文檔中的注釋?zhuān)ǜ鶕?jù)您的示例改編)顯示了您需要做的事情:給__set_name__自己打電話(huà)。


class D:

    def __init__(self, greeting='Hello'):

        self.greeting = greeting


    def greet(self):

        return self.greeting + " world!"


D.greet = cached_property(greet)

D.greet.__set_name__(D, 'greet')  # sets D.greet.attrname = "greet" for later use


assert D().greet == "hello world!"

為什么需要屬性名稱(chēng)?cached_property.__set__未定義,因此給定d = D(),d.greet將首先查找名為greetin的實(shí)例屬性d.__dict__。如果沒(méi)有找到,D.greet.__get__(d, D)則將被調(diào)用。該函數(shù)基本上做了三件事:如果需要計(jì)算值,它會(huì)調(diào)用原始greet函數(shù),然后將其保存到同名的新實(shí)例屬性中,然后返回計(jì)算值。


“等等”,你會(huì)問(wèn),“ ‘如果需要’是什么意思?你剛才不是說(shuō)D.greet.__get__只有當(dāng)實(shí)例屬性不存在時(shí)才被調(diào)用嗎? ”是的,但是在多線(xiàn)程環(huán)境中,你不知道另一個(gè)線(xiàn)程是否也可能同時(shí)執(zhí)行D.greet.__get__。為了防止競(jìng)爭(zhēng)條件,__get__請(qǐng)執(zhí)行以下步驟(如果您愿意,可以按照代碼進(jìn)行操作):

  1. 檢查具有相同名稱(chēng)的實(shí)例屬性,以防它是在當(dāng)前調(diào)用開(kāi)始后在另一個(gè)線(xiàn)程中創(chuàng)建的。

  2. 如果沒(méi)有,請(qǐng)嘗試獲取鎖,以便我們可以自己創(chuàng)建實(shí)例屬性。

  3. 獲得鎖后,再次查找實(shí)例屬性,以防在我們等待鎖時(shí)有人創(chuàng)建了它。

  4. 如果實(shí)例屬性仍然不存在,我們可以安全地自己創(chuàng)建它。

  5. 最后,無(wú)論我們從實(shí)例屬性中拉取一個(gè)值還是我們自己調(diào)用原始greet函數(shù),我們都可以返回該值。

考慮到所有這些,我會(huì)稱(chēng)這是一個(gè)限制而不是錯(cuò)誤,而是一個(gè)很容易解決的限制。此實(shí)現(xiàn)可能比嘗試不依賴(lài)屬性名稱(chēng)本身來(lái)維護(hù)必要映射的實(shí)現(xiàn)更簡(jiǎn)單。


查看完整回答
反對(duì) 回復(fù) 2022-12-20
?
呼喚遠(yuǎn)方

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

這既不是錯(cuò)誤也不是限制。Using__set_name__只是推斷屬性名稱(chēng)的一種不同方式——與常規(guī)類(lèi)語(yǔ)法一起使用時(shí)更可靠。


例如,__set_name__也適用于僅cached_property直接綁定到名稱(chēng)的匿名函數(shù):


from functools import cached_property

import random


class Bar:

    foo = cached_property(lambda self: random.random())


bar = bar()

print(bar.foo)  # 0.9901613829744336

print(bar.foo)  # 0.9901613829744336

相反,當(dāng)使用時(shí)cached_property.cached_property,值存儲(chǔ)不當(dāng)——即bar.<lambda>——阻止它隱藏屬性。


>>> functools_bar.__dict__

{'foo': 0.9901613829744336}

>>> cached_property_bar.__dict__

{'<lambda>': 0.7003011051281254}


查看完整回答
反對(duì) 回復(fù) 2022-12-20
  • 2 回答
  • 0 關(guān)注
  • 191 瀏覽
慕課專(zhuān)欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號(hào)

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