33面向?qū)ο?_descriptors-創(chuàng)新互聯(lián)

descriptors描述器:

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到西夏網(wǎng)站設(shè)計(jì)與西夏網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站制作、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、網(wǎng)站空間、企業(yè)郵箱。業(yè)務(wù)覆蓋西夏地區(qū)。

descriptor的表現(xiàn):

用到3個(gè)魔術(shù)方法:__get__()、__set__()、__delete__();

object.__get__(self,instance,owner)

object.__set__(self,instance,value)

object.__delete__(self,instance)

self,指代當(dāng)前實(shí)例,調(diào)用者;

instance,是owner的實(shí)例;

owner,是屬性所屬的類;

py中,一個(gè)類實(shí)現(xiàn)了__get__()、__set__()、__delete__()三個(gè)方法中的任何一個(gè)方法,就是描述器;

如果僅實(shí)現(xiàn)了__get__(),就是non-data descriptor非數(shù)據(jù)描述器;

如果同時(shí)實(shí)現(xiàn)了__get__()、__set__(),就是data descriptor數(shù)據(jù)描述器,如@property;

如果一個(gè)類的類屬性設(shè)置為描述器,那么這個(gè)類它被稱為owner屬主,如B類中類屬性x = A();

關(guān)鍵記?。侯悓傩裕?/p>

注:

當(dāng)一個(gè)類的類屬性,是另一個(gè)類的實(shí)例時(shí),這“另一個(gè)類”上有__get__()、__set__()、__delete__()三者之一,它就是個(gè)描述器的類,在類屬性上訪問(wèn)另一個(gè)類的實(shí)例時(shí),它就會(huì)觸發(fā)__get__()方法;如果是通過(guò)實(shí)例的屬性訪問(wèn)另一個(gè)類的實(shí)例self.x = A(),它不會(huì)觸發(fā)__get__()方法;

non-data descriptor和data descriptor:

理解1:

如果一個(gè)類的屬性是一個(gè)數(shù)據(jù)描述器,對(duì)實(shí)例屬性的操作(該實(shí)例屬性與類屬性名相同時(shí))相當(dāng)于操作類屬性;

理解2:

官方是用優(yōu)先級(jí)定義的;

一個(gè)類的類屬性是一個(gè)數(shù)據(jù)描述器,對(duì)該類的實(shí)例屬性的操作,該類的實(shí)例的__dict__優(yōu)先級(jí)降低(數(shù)據(jù)描述器的優(yōu)先級(jí)高于實(shí)例的__dict__);

如果是非數(shù)據(jù)描述器,則實(shí)例的__dict__高于描述器的優(yōu)先級(jí);

屬性查找順序:

實(shí)例的__dict__優(yōu)先于non-data descriptor;

data descriptor優(yōu)先于實(shí)例的__dict__;

__delete__有同樣的效果,有此方法就是data descriptor;

B.x = 500?? #對(duì)描述器不能這么用,賦值即定義,直接把類屬性覆蓋了,注意,不要直接用類來(lái)操作,盡管是在類上定義,也要用實(shí)例來(lái)操作,除非明確知道在干什么

print(B.x)

b = B()

b.x = 600?? #雖觸發(fā)了__set__(),未把類屬性覆蓋,也寫不進(jìn)__dict__中,被__set__()攔截了,對(duì)數(shù)據(jù)起到一定保護(hù)作用

本質(zhì):

查看實(shí)例的__dict__可知,data descriptor,實(shí)例的__dict__都被__set__()攔住,實(shí)例的屬性名與類屬性名相同時(shí),寫不進(jìn)實(shí)例的__dict__中;

原來(lái)不是什么data descriptor優(yōu)先級(jí)高,而是把實(shí)例的屬性從__dict__中給去掉了(實(shí)例的屬性名與類的屬性名相同),造成了該屬性如果是data descriptor優(yōu)先訪問(wèn)的假象,說(shuō)到底,屬性訪問(wèn)的順序從來(lái)就沒(méi)變過(guò);

py的描述器應(yīng)用非常廣泛;

py的所有方法(包括@staticmethod、@classmethod、__init__()),都是non-data descriptor,因此,實(shí)例可以重新定義和覆蓋方法,這允許單個(gè)實(shí)例獲取與同一類的其它實(shí)例不同的行為;

@property類實(shí)現(xiàn)是一個(gè)data descriptor,因此,實(shí)例不能覆蓋屬性的行為;

例:

class A:

def __init__(self):

print('A.__init__')

self.a1 = 'a1'

class B:

x = A()

def __init__(self):

print('B.__init__')

self.x = 100

print(B.x.a1)

b = B()

# print(b.x.a1)?? # X,AttributeError: 'int' object has no attribute 'a1'

輸出:

A.__init__

a1

B.__init__

例:

class A:

def __init__(self):

print('A.__init__')

self.a1 = 'a1'

def __get__(self, instance, owner): ??#類A中定義了__get__(),類A就是一個(gè)描述器,對(duì)類B的屬性x讀取,成為對(duì)類A的實(shí)例的訪問(wèn)就會(huì)調(diào)用__get__()

print('A.__get__',self,instance,owner)

# return self?? #解決B.x.a1報(bào)錯(cuò)NoneType問(wèn)題,黑魔法,通過(guò)屬性描述器來(lái)操作屬主,拿到屬主的類,可動(dòng)態(tài)的改所有屬性

class B:

x = A()?? #當(dāng)一個(gè)類的類屬性,是另一個(gè)類的實(shí)例時(shí),這“另一個(gè)類”上有__get__()、__set__()、__delete__()三者之一,它就是個(gè)描述器的類,在類屬性上訪問(wèn)另一個(gè)類的實(shí)例時(shí),它就會(huì)觸發(fā)__get__()方法

def __init__(self):

print('B.__init__')

# self.x = 100

self.x = A()?? #如果是通過(guò)實(shí)例的屬性訪問(wèn)另一個(gè)類的實(shí)例self.x = A(),它不會(huì)觸發(fā)__get__()方法

print(B.x)??#V,要在類屬性上訪問(wèn),才觸發(fā)__get__(),該例__get__()方法返回None

# print(B.x.a1)?? #X,AttributeError: 'NoneType' object has no attribute 'a1',解決辦法:在類A的__get__()添加返回值return self

b = B()

print(b.x)

print(b.x.a1)?? #實(shí)例屬性上訪問(wèn)不會(huì)觸發(fā)__get__()

輸出:

A.__init__

A.__get__ <__main__.A object at 0x7f3d53b2bb38> None <class '__main__.B'> ??#依次為A的實(shí)例,None沒(méi)有類B的實(shí)例,類B

None

B.__init__

A.__init__

<__main__.A object at 0x7f3d53b2bba8>

a1

例:

class A:

def __init__(self):

print('A.__init__')

self.a1 = 'a1test'

def __get__(self, instance, owner):

print('A.__get__',self,instance,owner)

return self

def __set__(self, instance, value):?? #有__set__()后,類B的實(shí)例b的__dict__為空,只能向上訪問(wèn)類屬性的

print('A.__set__',self,instance,value)

class B:

x = A()

def __init__(self):

print('B.__init__')

# self.x = 100

self.x = A()

print(B.x)

print("*"*20)

print(B.x.a1)

print("#"*20)

b = B()?? #觸發(fā)__set__()

print("*"*20)

print(b.x)?? #數(shù)據(jù)描述器,對(duì)實(shí)例屬性的操作(該實(shí)例屬性與類屬性的名字相同)相當(dāng)于操作類屬性,查看實(shí)例的__dict__(為空)可知(向上找了類屬性)

print("*"*20)

print(b.x.a1)

print("#"*20)

print(b.__dict__)

print(B.__dict__)

# B.x = 500?? #對(duì)描述器不能這么用,賦值即定義,直接把類屬性覆蓋了,注意,不要直接用類來(lái)操作,盡管是在類上定義,也要用實(shí)例來(lái)操作,除非明確知道在干什么

# print(B.x)

輸出:

A.__init__

A.__get__ <__main__.A object at 0x7f63acbcd400> None <class '__main__.B'>

<__main__.A object at 0x7f63acbcd400>

********************

A.__get__ <__main__.A object at 0x7f63acbcd400> None <class '__main__.B'>

a1test

####################

B.__init__

A.__init__

A.__set__ <__main__.A object at 0x7f63acbcd400> <__main__.B object at 0x7f63acbcdb70> <__main__.A object at 0x7f63acbcdba8>

********************

A.__get__ <__main__.A object at 0x7f63acbcd400> <__main__.B object at 0x7f63acbcdb70> <class '__main__.B'>

<__main__.A object at 0x7f63acbcd400>

********************

A.__get__ <__main__.A object at 0x7f63acbcd400> <__main__.B object at 0x7f63acbcdb70> <class '__main__.B'>

a1test

####################

{}

{'__module__': '__main__', 'x': <__main__.A object at 0x7f63acbcd400>, '__init__': <function B.__init__ at 0x7f63acbca510>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}

例:

class A:

def __init__(self):

print('A.__init__')

self.a1 = 'a1test'

def __get__(self, instance, owner):

print('A.__get__',self,instance,owner)

return self

def __set__(self, instance, value):

print('A.__set__',self,instance,value)

class B:

x = A()

def __init__(self):

print('B.__init__')

# self.x = 100

self.x = A()

b = B()

print("*"*20)

b.x = 600?? #雖觸發(fā)了__set__(),未把類屬性覆蓋,也寫不進(jìn)實(shí)例的__dict__中(查看實(shí)例的__dict__可知),被__set__()攔截了,對(duì)數(shù)據(jù)起到一定保護(hù)作用

print("*"*20)

print(b.x)?? #調(diào)用__get__()

print("*"*20)

print(b.__dict__)

輸出:

A.__init__

B.__init__

A.__init__

A.__set__ <__main__.A object at 0x7f05dd15eb70> <__main__.B object at 0x7f05dd15eba8> <__main__.A object at 0x7f05dd15ebe0>

********************

A.__set__ <__main__.A object at 0x7f05dd15eb70> <__main__.B object at 0x7f05dd15eba8> 600

********************

A.__get__ <__main__.A object at 0x7f05dd15eb70> <__main__.B object at 0x7f05dd15eba8> <class '__main__.B'>

<__main__.A object at 0x7f05dd15eb70>

********************

{}

習(xí)題:

1、實(shí)現(xiàn)StaticMethod裝飾器,完成staticmethod裝飾器的功能;

2、實(shí)現(xiàn)ClassMethod裝飾器,完成classmethod裝飾器的功能;

3、對(duì)實(shí)例的數(shù)據(jù)進(jìn)行校驗(yàn);

class Person:

def __init__(self,name:str,age:int):

self.name = name

self.age = age

1、

class StaticMethod:

def __init__(self,fn):

# print('__init__',fn)

self.fn = fn

def __get__(self, instance, owner):

# print('__get__',self,instance,owner)

return self.fn

class A:

@StaticMethod

def foo():?? #類裝飾器裝飾完后,原函數(shù)消失了,foo=StaticMethod(foo),成為裝飾器類的實(shí)例了,在類屬性上訪問(wèn)另一個(gè)類的實(shí)例時(shí)就會(huì)觸發(fā)__get__()方法

print('test function')

@staticmethod

def foo2():

print('test2 func')

f = A.foo

print(f)

f()

A.foo2()

A().foo()

A().foo2()

輸出

<function A.foo at 0x7fd0675bb488>

test function

test2 func

test function

test2 func

2、

from functools import partial

class ClassMethod:

def __init__(self,fn):

???print('__init__',fn)

self.fn = fn

def __get__(self, instance, cls):

print('__get__', self, instance, cls)

# return self.fn(cls)?? #X,NoneType

?return partial(self.fn, cls)?? #固定下來(lái),返回一個(gè)新函數(shù)

class A:

@ClassMethod

def bar(cls):

print(cls.__name__)

# print(A.bar)

# print()

A.bar()

print()

A().bar()

print()

print(A.__dict__)

輸出:

__init__ <function A.bar at 0x7f2998f97e18>

__get__ <__main__.ClassMethod object at 0x7f2999039d68> None <class '__main__.A'>

A

__get__ <__main__.ClassMethod object at 0x7f2999039d68> <__main__.A object at 0x7f2999039da0> <class '__main__.A'>

A

{'__module__': '__main__', 'bar': <__main__.ClassMethod object at 0x7f2999039d68>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

3、

class Typed:

def __init__(self,type):

self.type = type

def __get__(self, instance, owner):

pass

def __set__(self, instance, value):

print('T.__set__',self,instance,value)

if not isinstance(value,self.type):

raise ValueError('value')

class Person:

name = Typed(str)?? #硬編碼,需改進(jìn)

age = Typed(int)

def __init__(self,name:str,age:int):

self.name = name

self.age = age

p1 = Person('tom',18)

3、

改進(jìn):用裝飾器+描述器,py中大量使用;

import inspect

class Typed:

def __init__(self, type):

self.type = type

def __get__(self, instance, owner):

pass

def __set__(self, instance, value):

print('set', self, instance, value)

if not isinstance(value, self.type):

raise ValueError(value)

class TypeAssert:

def __init__(self, cls):

self.cls = cls

params = inspect.signature(self.cls).parameters

# print(params)

for name, param in params.items():

print(name, param.annotation)

if param.annotation != param.empty:

setattr(self.cls, name, Typed(param.annotation))?? #動(dòng)態(tài)類屬性注入

def __call__(self, name, age):

# params = inspect.signature(self.cls).parameters

# print(params)

# for name,param in params.items():

#???? print(name,param.annotation)

#???? if param.annotation != param.empty:

#???????? setattr(self.cls,name,Typed(param.annotation))

p = self.cls(name, age)

return p

@TypeAssert

class Person:

# name = Typed(str)?? #動(dòng)態(tài)類屬性注入

# age = Typed(age)

def __init__(self, name: str, age: int):

self.name = name

self.age = age

p1 = Person('jerry', 18)

p2 = Person('tom', 16)

print(id(p1))

print(id(p2))

輸出:

name <class 'str'>

age <class 'int'>

set <__main__.Typed object at 0x7f596a121da0> <__main__.Person object at 0x7f596a121dd8> jerry

set <__main__.Typed object at 0x7f596a121cf8> <__main__.Person object at 0x7f596a121dd8> 18

set <__main__.Typed object at 0x7f596a121da0> <__main__.Person object at 0x7f596a0af940> tom

set <__main__.Typed object at 0x7f596a121cf8> <__main__.Person object at 0x7f596a0af940> 16

140022008389080

140022007920960

習(xí)題:

1、將鏈表,封裝成容器:

要求:

1)提供__getitem__()、__iter__()、__setitem__();

2)使用一個(gè)列表,輔助完成上面的方法;

3)進(jìn)階:不使用列表,完成上面的方法;

2、實(shí)現(xiàn)類property裝飾器,類名稱為Property;

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

網(wǎng)站題目:33面向?qū)ο?_descriptors-創(chuàng)新互聯(lián)
地址分享:http://bm7419.com/article28/ggpcp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開(kāi)發(fā)關(guān)鍵詞優(yōu)化、自適應(yīng)網(wǎng)站、網(wǎng)站制作、網(wǎng)站導(dǎo)航、外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)