亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么屬性類屬性在 Python 中?

為什么屬性類屬性在 Python 中?

MMTTMM 2021-06-03 05:11:33
我正在閱讀Fluent Python 第 19 章 > A Proper Look at Properties,我對以下單詞感到困惑:屬性始終是類屬性,但它們實際上管理類實例中的屬性訪問。示例代碼是:class LineItem:    def __init__(self, description, weight, price):        self.description = description        self.weight = weight  # <1>        self.price = price    def subtotal(self):        return self.weight * self.price    @property  # <2>    def weight(self):  # <3>        return self.__weight  # <4>    @weight.setter  # <5>    def weight(self, value):        if value > 0:            self.__weight = value  # <6>        else:            raise ValueError('value must be > 0')  # <7>根據我以前的經驗,類屬性屬于類本身,并由所有實例共享。但是這里,weight,屬性,是一個實例方法,它返回的值在實例之間是不同的。它如何有資格成為類屬性?對于任何實例,所有類屬性不是都應該相同嗎?我想我誤解了一些東西,所以我希望得到一個正確的解釋。謝謝!
查看完整描述

3 回答

?
青春有我

TA貢獻1784條經驗 獲得超8個贊

通過Simeon Franklin的精彩演講,我終于明白了描述符和屬性的概念,下面的內容可以看作是他的講義的總結。感謝他!


要了解屬性,首先需要了解描述符,因為屬性是由描述符和python 的裝飾器語法糖實現的。別擔心,這并不難。


什么是描述符:


一個描述符是的方法實現了至少一個命名__get任何對象__(),__set __(),和__delete __()。

描述符可以分為兩類:


甲數據描述符同時實現__get __()和__set __()。

阿非數據描述符僅實現__get __()。

根據python 的 HowTo:


描述符是具有“綁定行為”的對象屬性,其屬性訪問已被描述符協議中的方法覆蓋。


那么描述符協議是什么呢?基本上來說,就是說當Python解釋器遇到像這樣的屬性訪問時obj.attr,它會按某種順序搜索來解決這個問題.attr,如果這attr是一個描述符屬性,那么這個描述符會在這個特定的順序和這個屬性訪問中占有一定的優先級將根據描述符協議轉換為對該描述符的方法調用,可能隱藏同名實例屬性或類屬性。更具體地說,如果attr是一個數據描述符,那么obj.attr會被翻譯成這個描述符的__get__方法的調用結果;如果attr不是數據描述符而是實例屬性,則匹配此實例屬性;如果attr不在上面,而且是一個非數據描述符,我們得到這個非數據描述符的 __get__ 方法的調用結果??梢栽诖颂幷业接嘘P屬性解析的完整規則。


現在讓我們談談財產。如果您查看過Python 的描述符 HowTo,您可以找到屬性的純 Python 版本實現:


class Property(object):

    "Emulate PyProperty_Type() in Objects/descrobject.c"


    def __init__(self, fget=None, fset=None, fdel=None, doc=None):

        self.fget = fget

        self.fset = fset

        self.fdel = fdel

        if doc is None and fget is not None:

            doc = fget.__doc__

        self.__doc__ = doc


    def __get__(self, obj, objtype=None):

        if obj is None:

            return self

        if self.fget is None:

            raise AttributeError("unreadable attribute")

        return self.fget(obj)


    def __set__(self, obj, value):

        if self.fset is None:

            raise AttributeError("can't set attribute")

        self.fset(obj, value)


    def __delete__(self, obj):

        if self.fdel is None:

            raise AttributeError("can't delete attribute")

        self.fdel(obj)


    def getter(self, fget):

        return type(self)(fget, self.fset, self.fdel, self.__doc__)


    def setter(self, fset):

        return type(self)(self.fget, fset, self.fdel, self.__doc__)


    def deleter(self, fdel):

        return type(self)(self.fget, self.fset, fdel, self.__doc__)

顯然,property 是一個數據描述符!


@property 只是使用 python 的裝飾器語法糖。


@property

def attr(self):

    pass

相當于:


attr = property(attr)

所以,attr不再是我在 thie question 中發布的實例方法,而是像作者所說的那樣被裝飾器語法糖翻譯成一個類屬性。它是一個描述符對象屬性。


它如何有資格成為類屬性?


好的,我們現在解決了。


然后:


對于任何實例,所有類屬性不是都應該相同嗎?


不!


我從Simeon Franklin 的精彩演講中竊取了一個例子。


>>> class MyDescriptor(object):

...     def __get__(self, obj, type):

...         print self, obj, type

...     def __set__(self, obj, val):

...         print "Got %s" % val

...

>>> class MyClass(object):

...     x = MyDescriptor() # Attached at class definition time!

...

>>> obj = MyClass()

>>> obj.x # a function call is hiding here

<...MyDescriptor object ...> <....MyClass object ...> <class '__main__.MyClass'>

>>>

>>> MyClass.x # and here!

<...MyDescriptor object ...> None <class '__main__.MyClass'>

>>>

>>> obj.x = 4 # and here

Got 4

注意obj.x和它的輸出。其輸出中的第二個元素是<....MyClass object ...>。這是特定的實例obj。簡而言之,因為這個屬性訪問已經被翻譯成了一個__get__方法調用,而這個__get__方法按照其方法簽名的descr.__get__(self, obj, type=None)要求獲取了具體的實例參數,它可以根據調用它的實例返回不同的值。


注意:我的英文解釋可能不夠清楚,所以我強烈建議你看看 Simeon Franklin 的筆記和 Python 的描述符 HowTo。


查看完整回答
反對 回復 2021-06-09
  • 3 回答
  • 0 關注
  • 192 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號