bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

33面向對象8_descriptors-創新互聯

descriptors描述器:

站在用戶的角度思考問題,與客戶深入溝通,找到西夏網站設計與西夏網站推廣的解決方案,憑借多年的經驗,讓設計與互聯網技術結合,創造個性化、用戶體驗好的作品,建站類型包括:成都網站制作、成都做網站、企業官網、英文網站、手機端網站、網站推廣、域名注冊網站空間、企業郵箱。業務覆蓋西夏地區。

descriptor的表現:

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

object.__get__(self,instance,owner)

object.__set__(self,instance,value)

object.__delete__(self,instance)

self,指代當前實例,調用者;

instance,是owner的實例;

owner,是屬性所屬的類;

py中,一個類實現了__get__()、__set__()、__delete__()三個方法中的任何一個方法,就是描述器;

如果僅實現了__get__(),就是non-data descriptor非數據描述器;

如果同時實現了__get__()、__set__(),就是data descriptor數據描述器,如@property;

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

關鍵記住:類屬性;

注:

當一個類的類屬性,是另一個類的實例時,這“另一個類”上有__get__()、__set__()、__delete__()三者之一,它就是個描述器的類,在類屬性上訪問另一個類的實例時,它就會觸發__get__()方法;如果是通過實例的屬性訪問另一個類的實例self.x = A(),它不會觸發__get__()方法;

non-data descriptor和data descriptor:

理解1:

如果一個類的屬性是一個數據描述器,對實例屬性的操作(該實例屬性與類屬性名相同時)相當于操作類屬性;

理解2:

官方是用優先級定義的;

一個類的類屬性是一個數據描述器,對該類的實例屬性的操作,該類的實例的__dict__優先級降低(數據描述器的優先級高于實例的__dict__);

如果是非數據描述器,則實例的__dict__高于描述器的優先級;

屬性查找順序:

實例的__dict__優先于non-data descriptor;

data descriptor優先于實例的__dict__;

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

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

print(B.x)

b = B()

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

本質:

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

原來不是什么data descriptor優先級高,而是把實例的屬性從__dict__中給去掉了(實例的屬性名與類的屬性名相同),造成了該屬性如果是data descriptor優先訪問的假象,說到底,屬性訪問的順序從來就沒變過;

py的描述器應用非常廣泛;

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

@property類實現是一個data descriptor,因此,實例不能覆蓋屬性的行為;

例:

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就是一個描述器,對類B的屬性x讀取,成為對類A的實例的訪問就會調用__get__()

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

# return self?? #解決B.x.a1報錯NoneType問題,黑魔法,通過屬性描述器來操作屬主,拿到屬主的類,可動態的改所有屬性

class B:

x = A()?? #當一個類的類屬性,是另一個類的實例時,這“另一個類”上有__get__()、__set__()、__delete__()三者之一,它就是個描述器的類,在類屬性上訪問另一個類的實例時,它就會觸發__get__()方法

def __init__(self):

print('B.__init__')

# self.x = 100

self.x = A()?? #如果是通過實例的屬性訪問另一個類的實例self.x = A(),它不會觸發__get__()方法

print(B.x)??#V,要在類屬性上訪問,才觸發__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)?? #實例屬性上訪問不會觸發__get__()

輸出:

A.__init__

A.__get__ <__main__.A object at 0x7f3d53b2bb38> None <class '__main__.B'> ??#依次為A的實例,None沒有類B的實例,類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的實例b的__dict__為空,只能向上訪問類屬性的

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()?? #觸發__set__()

print("*"*20)

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

print("*"*20)

print(b.x.a1)

print("#"*20)

print(b.__dict__)

print(B.__dict__)

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

# 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?? #雖觸發了__set__(),未把類屬性覆蓋,也寫不進實例的__dict__中(查看實例的__dict__可知),被__set__()攔截了,對數據起到一定保護作用

print("*"*20)

print(b.x)?? #調用__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>

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

{}

習題:

1、實現StaticMethod裝飾器,完成staticmethod裝飾器的功能;

2、實現ClassMethod裝飾器,完成classmethod裝飾器的功能;

3、對實例的數據進行校驗;

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():?? #類裝飾器裝飾完后,原函數消失了,foo=StaticMethod(foo),成為裝飾器類的實例了,在類屬性上訪問另一個類的實例時就會觸發__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)?? #固定下來,返回一個新函數

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)?? #硬編碼,需改進

age = Typed(int)

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

self.name = name

self.age = age

p1 = Person('tom',18)

3、

改進:用裝飾器+描述器,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))?? #動態類屬性注入

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)?? #動態類屬性注入

# 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

習題:

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

要求:

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

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

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

2、實現類property裝飾器,類名稱為Property;

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

網站題目:33面向對象8_descriptors-創新互聯
地址分享:http://vcdvsql.cn/article28/ggpcp.html

成都網站建設公司_創新互聯,為您提供小程序開發、關鍵詞優化、自適應網站、網站制作網站導航、外貿網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

外貿網站建設