国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

python 描述符解析

rozbo / 942人閱讀

摘要:之所以是這樣是因?yàn)楫?dāng)訪問一個實(shí)例描述符對象時,會將轉(zhuǎn)換為。而類的字典中則有描述符對象。這主要就是因?yàn)槊枋龇麅?yōu)先。此外,非數(shù)據(jù)描述符的優(yōu)先級低于實(shí)例屬性。參考以上就是本人對描述符的一些理解,有什么不正確的地方還請不吝指出,謝謝

什么是描述符

python描述符是一個“綁定行為”的對象屬性,在描述符協(xié)議中,它可以通過方法重寫屬性的訪問。這些方法有 __get__(), __set__(), 和__delete__()。如果這些方法中的任何一個被定義在一個對象中,這個對象就是一個描述符。

描述符的調(diào)用

描述符作為屬性訪問是被自動調(diào)用的。

對于類屬性描述符對象,使用type.__getattribute__,它能把Class.x轉(zhuǎn)換成Class.__dict__["x"].__get__(None, Class)。
對于實(shí)例屬性描述符對象,使用object.__getattribute__,它能把object.x轉(zhuǎn)換為type(object).__dict__["x"].__get__(object, type(object))。

描述符講解

下面我們具體通過實(shí)例來詳細(xì)說明描述符的使用

先定義一個描述符

class RevealAccess(object):

    def __init__(self, initval=None, name="var"):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print "Retrieving", self.name
        return self.val

    def __set__(self, obj, val):
        print "Updating", self.name
        self.val = val

上面實(shí)現(xiàn)了__get__和__set__。所以這是一個描述符對象。而且是一個數(shù)據(jù)描述符對象,非數(shù)據(jù)描述符對象只實(shí)現(xiàn)__get__方法。這2者之間有一些區(qū)別,下面會講到。

再定義一個調(diào)用描述符對象的類

class MyClass(object):
    x = RevealAccess(10, "var "x"")
    y = 5

print MyClass.x

訪問 MyClass.x 輸出

Retrieving var "x"
10

發(fā)現(xiàn)訪問x會去調(diào)用描述符的__get__方法。這就達(dá)到了描述符的作用,可以改變對象屬性的訪問,使用描述符的方法。因?yàn)槿绻馕銎靼l(fā)現(xiàn)x是一個描述符的話,其實(shí)在內(nèi)部是通過type.__getattribute__(),它能把MyClass.x轉(zhuǎn)換為MyClass.__dict__[“x”].__get__(None,MyClass)來訪問。

print MyClass.__dict__["x"].__get__(None, MyClass)
# 輸出
Retrieving var "x"
10

描述符的對象定義為類屬性,如果定義成對象屬性會有什么不同嗎?下面我們試驗(yàn)一下

class MyClass(object):

    x = RevealAccess(10, "var "x"")

    def __init__(self):
        self.y = RevealAccess(11, "var "y"")

print type(MyClass.x)
# 輸出
"""
Retrieving var "x"
;
"""
test = MyClass()
print test.y
# 輸出 
"""
<__main__.RevealAccess object at 0x1004da410>;
"""

從上面的輸出,可以看到訪問類屬性的確調(diào)用了描述符的__get__方法,看到輸出的結(jié)果是int類型。而調(diào)用實(shí)例屬性并沒有訪問__get__方法。而是直接返回描述符的實(shí)例對象。之所以是這樣是因?yàn)楫?dāng)訪問一個實(shí)例描述符對象時,object.__getattribute__會將test.y轉(zhuǎn)換為type(test).__dict__[‘y’].__get__(test,type(test))
而MyClass類中沒有“y”屬性,所以無法訪調(diào)用到_get__方法,這里會有一個判斷的過程。但這個實(shí)例對象仍然是一個描述符對象。所以最好定義描述符對象為類屬性。當(dāng)然不是不可以定義為實(shí)例屬性,請看下面

當(dāng)定義的類屬性描述符對象和實(shí)例屬性有相同的名字時

class MyClass(object):
     
    x = RevealAccess(10, "var "x"")

    def __init__(self, x):
        self.x = x

然后調(diào)用

test = MyClass(100)
print test.x
# 輸出
"""
Updating var "x"
Retrieving var "x"
100
"""

可見依然調(diào)用了描述符的方法。按照常理,應(yīng)該訪問 test.__dict__["x"],然后是type(test).__dict__["x"]。由于我們定義了實(shí)例屬性x。應(yīng)該只輸出100。可這里從輸出結(jié)果看的的確確的訪問了描述符的方法。那么這是為什么呢?

其實(shí)這里主要是因?yàn)楫?dāng)python發(fā)現(xiàn)實(shí)例對象的字典中有與定義的描述符有相同名字的對象時,描述符優(yōu)先,會覆蓋掉實(shí)例屬性。python會改寫默認(rèn)的行為,去調(diào)用描述符的方法來代替。我們可以輸出類和實(shí)例對象的字典看看

test = MyClass(100)
print test.__dict__
"""
輸出 {}
"""
print MyClass.__dict__
"""
輸出 {"__module__": "__main__", "__dict__": , 
"x": <__main__.RevealAccess object at 0x1004da350>, 
"__weakref__": , 
"__doc__": None, "__init__": }
"""

從輸出中發(fā)現(xiàn)實(shí)例對象的字典中根本就沒有x對象,即使我們在類中定義了self.x。而類的字典中則有x描述符對象。這主要就是因?yàn)槊枋龇麅?yōu)先。

上面我們定義的描述符有__get__和__set__2個方法,所以是一個數(shù)據(jù)描述符,非數(shù)據(jù)描述符只有一個__get__方法,通常用于方法。此外,非數(shù)據(jù)描述符的優(yōu)先級低于實(shí)例屬性。下面看一個例子,我們?nèi)サ鬫_set__方法。

class RevealAccess(object):
    def __init__(self, initval=None, name="var"):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print "Retrieving", self.name
        # self.val="test"
        return self.val

    # def __set__(self, obj, val):
        # print "Updating", self.name
        # self.val = val

class MyClass(object):
    x = RevealAccess(10, "var "x"")

    def __init__(self, x):
        self.x = x

test = MyClass(100)
print test.x
“”“
100
“”“
print test.__dict__
“”“
{"x": 100}
“”“
print MyClass.__dict__
“”“
{"__module__": "__main__", "__dict__": ,
"x": <;__main__.RevealAccess object at 0x1005da310>, 
"__weakref__": , 
"__doc__": None, "__init__": }
“”“
print MyClass.x
"""
Retrieving var "x"
10
"""

從上面的輸出,可以看出非數(shù)據(jù)描述符不會覆蓋掉實(shí)例屬性。而且優(yōu)先級比實(shí)例屬性低。這也是和數(shù)據(jù)描述符的一個區(qū)別。

綜上所述,對于描述符的調(diào)用有以下幾點(diǎn)需要注意

描述符被 getattribute 方法調(diào)用

覆蓋__getattribute__會讓描述符無法自動調(diào)用

描述符只適用于新式類,即繼承object的類

object . getattribute 和 type . getattribute 調(diào)用__get__方法不一樣

數(shù)據(jù)描述符優(yōu)先于實(shí)例的字典,對于相同名字的會覆蓋

實(shí)例的字典優(yōu)先于非數(shù)據(jù)描述符。但不會覆蓋。

對于數(shù)據(jù)描述符,python中property就是一個典型的應(yīng)用。

對于非數(shù)據(jù)描述符,其主要用于方法。如靜態(tài)方法和類方法。看源碼可以看到只實(shí)現(xiàn)了描述符協(xié)議中的__get__方法,而沒有實(shí)現(xiàn)__set__和__del__。

如下面這樣模擬靜態(tài)方法

class StaticMethod(object):
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f

class MyClass(object):

    @StaticMethod
    def get_x(x):
        print("static")
        return x

print MyClass.get_x(100)
"""
static
100
“”“

調(diào)用MyClass.get_x(100)相當(dāng)于

MyClass.__dict__["get_x"].__get__(None, MyClass)(100)

我們知道在python中,一切皆是對象。每一個定義的方法其實(shí)都是一個對象。在這里我們可以通過dir()查看每一個方法里的屬性和方法。看下面

class Desc(object):
    def test1(self):
        print("test1")

def test2():
    print("test2")
print(dir(test2))
"""輸出太長不貼了,但從輸出中可以看到有__get__"""
print(dir(Desc.test1))
"""
["__call__", "__class__", "__cmp__", "__delattr__", "__doc__", "__format__", "__func__",
 "__get__", "__getattribute__", "__hash__", "__init__", "__new__", "__reduce__", 
"__reduce_ex__", "__repr__", "__self__", "__setattr__", "__sizeof__", 
"__str__", "__subclasshook__", "im_class", "im_func", "im_self"]
"""

從dir的輸出,可以看到,每個方法對象都包含一個__get__方法。因此可以說每一個方法都是一個非數(shù)據(jù)描述符。通常我們通過點(diǎn)操作符調(diào)用方法時,內(nèi)部都是調(diào)用這個__get__方法。

參考 https://docs.python.org/2.7/h...

以上就是本人對描述符的一些理解,有什么不正確的地方還請不吝指出,謝謝!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/38242.html

相關(guān)文章

  • Bottle框架中的裝飾器類和描述應(yīng)用

    摘要:最近在閱讀微型框架的源碼,發(fā)現(xiàn)了中有一個既是裝飾器類又是描述符的有趣實(shí)現(xiàn)。所以第三版的代碼可以這樣寫第三版的代碼沒有使用裝飾器,而是使用了描述符這個技巧。更大的問題來自如何將描述符與裝飾器結(jié)合起來,因?yàn)槭且粋€類而不是方法。 最近在閱讀Python微型Web框架Bottle的源碼,發(fā)現(xiàn)了Bottle中有一個既是裝飾器類又是描述符的有趣實(shí)現(xiàn)。剛好這兩個點(diǎn)是Python比較的難理解,又混合在...

    Panda 評論0 收藏0
  • Python之父發(fā)文吐槽現(xiàn)有解析器,考慮將它替換掉

    摘要:近日,他開通了賬號,并發(fā)表了第一篇文章,透露出要替換的核心部件解析器的想法。這篇文章分析了當(dāng)前的解析器的諸多缺陷,并介紹了解析器的優(yōu)點(diǎn),令人振奮。但問題是,如果你這樣寫語法,解析器不會起作用,將會罷工。 showImg(https://segmentfault.com/img/remote/1460000019893712?w=3936&h=2624); 花下貓語: Guido van...

    xiaoxiaozi 評論0 收藏0
  • Python中的屬性描述

    摘要:下面我們用描述符來實(shí)現(xiàn)中的動態(tài)屬性和特性中提及的訂單結(jié)算代碼第四版使用描述符實(shí)現(xiàn)訂單結(jié)算功能描述符基于協(xié)議實(shí)現(xiàn),無需創(chuàng)建子類。特性是覆蓋型描述符。非覆蓋型描述符沒有實(shí)現(xiàn)方法的描述符屬于非覆蓋型描述符。類中定義的方法是非覆蓋型描述符。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之元編程篇的重點(diǎn)知識及個人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、了解描述符...

    geekzhou 評論0 收藏0
  • 90 % 的 Python 開發(fā)者不知道的描述應(yīng)用

    摘要:由上面的注釋,可以看出其實(shí)就相當(dāng)于一個描述符類,而在此刻變成了一個描述符。調(diào)用這個方法可以知道,每調(diào)用一次,它都會經(jīng)過描述符類的。基于描述符如何實(shí)現(xiàn)同樣的也是一樣。我想你應(yīng)該對描述符在中的應(yīng)用有了更深的理解。好吧,我承認(rèn)我標(biāo)題黨了。但是這篇文章的知識點(diǎn),你有極大的可能并不知道。 前段時間,我寫了一篇描述符的入門級文章,從那些文章里你知道了如何定義描述符,且明白了描述符是如何工作的。 如果你還...

    番茄西紅柿 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<