日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

描述符

發布時間:2023/12/2 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 描述符 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
描述符

描述符也是面向進階的一種,由于它的涉及比較廣,所以單獨講。

一、描述符

描述符本質就是一個新式類,在這個新式類中,至少實現了__get__(),__set__(),__delete__()中的一個,這也被稱為描述符協議。

描述符的作用是用來代理另外一個類的屬性,必須把描述符定義成一個類的類屬性,不能定義到構造函數中。

描述符分為兩種,一種是數據描述符:至少實現了__get__()和__set__();另一種是非數據描述符:沒有實現__set__()。

1.描述符格式

class Foo: #在python3中任何類都是新式類,它只要實現了三種方法之一,那么這個類就被稱作一個描述符def __get__(self, instance, owner): #調用一個屬性時觸發passdef __set__(self, instance, value): #為一個屬性賦值時觸發passdef __delete__(self, instance): #采用del刪除屬性時觸發pass

2.描述符的使用

描述符該如何使用呢?具體代碼如下:

class Foo: #描述符def __get__(self, instance, owner):print('我是get方法')def __set__(self, instance, value):print('我是set方法')def __delete__(self, instance):print('我是delete方法') class Bar:x = Foo() #把描述符代理一個類的屬性def __init__(self,n): self.x = nb1 = Bar(10) b1.x = 11111 b1.x del b1.x

執行代碼結果為:

我是set方法 我是set方法 我是get方法 我是delete方法

可以看出在實例化時也會觸發__set__方法,因為在類Bar的初始化函數中self.x是被描述符代理的屬性。那么對象b1中的屬性字典中到底存不存在x這個值呢?具體代碼如下所示:

class Foo(): #描述符def __get__(self, instance, owner):print('我是get方法')def __set__(self, instance, value):print('我是set方法')def __delete__(self, instance):print('我是delete方法') class Bar:x = Foo()def __init__(self,n): self.x = nb1 = Bar(10) print(b1.__dict__) b1.x = 11111 print(b1.__dict__)

執行結果為:

我是set方法 {} 我是set方法 {}

這是什么情況?無論是實例化操作還是賦值操作,在對象b1的屬性字典中仍然為空。正是因為描述符的關系,它相當于把被描述符的類的調用屬性操作、賦值操作、刪除操作都賦予另一個類來實現,跟本身類并沒有關系,當然這關系到優先級的問題。

3.描述符的優先級

我們要嚴格遵守優先級:類屬性>數據描述符>實例屬性>非數據描述符>找不到的屬性觸發__getattr__()。

(1)我們先對類屬性>數據描述符進行分析,具體代碼如下:

class Foo():def __get__(self, instance, owner):print('我是get方法')def __set__(self, instance, value):print('我是set方法')def __delete__(self, instance):print('我是delete方法') class Bar:x = Foo()Bar.x=111 print(Bar.x) #結果為:111

上述代碼打印結果仍為111,并沒有執行數據描述符,是因為Bar類調用了本來要被描述符代理的屬性x進行了修改。所有類屬性的優先級比數據描述符高。

(2)數據描述符>實例屬性的分析代碼如下:

class Foo():def __get__(self, instance, owner):print('我是get方法')def __set__(self, instance, value):print('我是set方法')def __delete__(self, instance):print('我是delete方法') class Bar:x = Foo()b1 = Bar() b1.x #結果為:我是get方法 b1.x = 111 #結果為:我是set方法

上述代碼Foo類被定義成Bar類的類屬性,即對Bar類進行實例化,實例屬性只執行數據描述符的方法。說明了數據描述符的優先級高于實例屬性。

(3)實例屬性>非數據描述符的分析代碼如下:

class Foo():def __get__(self, instance, owner):print('我是get方法') class Bar:x = Foo()b1 = Bar() b1.x = 111 print(b1.__dict__) #結果為:{'x': 111}

上述代碼可以看出實例給自己屬性進行賦值操作,可以在實例的屬性字典中找到,這說明了實例屬性的優先級高于非數據描述符。

(4)非數據描述符>找不到的屬性觸發__getattr__()的分析代碼如下:

class Foo():def __get__(self, instance, owner):print('我是get方法') class Bar:x = Foo()def __getattr__(self, item):print('我是getattr方法') b1 = Bar() b1.x #結果為:我是get方法 b1.name #結果為:我是getattr方法

上述代碼可以看出找得到時觸發__get__方法,找不到就會觸發__getattr__方法。說明了非數據描述符的優先級高于找不到的屬性觸發__getattr__()。

4.描述符的應用

描述符可以應用到哪些場合呢?我們就來舉個例子,通過描述符機制來實現參數的賦值類型限制。即:

class Typed:def __init__(self,key,expected_type):self.key = keyself.expected_type = expected_typedef __get__(self, instance, owner):print('get方法')return instance.__dict__[self.key]def __set__(self, instance, value):print('set方法')if not isinstance(value,self.expected_type):raise TypeError('你傳入的類型不是%s' %self.expected_type)instance.__dict__[self.key] = valuedef __delete__(self, instance):print('delete方法')instance.__dict__.pop(self.key) class People:name = Typed('name',str)age = Typed('age',int)salary = Typed('salary',float)def __init__(self,name,age,salary):self.name = nameself.age = ageself.salary = salaryp1 = People('alex',18,6666.66) p2 = People(250,26,4568.55) #不符合賦值類型,拋出異常

上述代碼對象p1是滿足參數的賦值類型,所以會觸發三次__set__方法。而對象p2不符合賦值類型,就會拋出異常。

5.propetry

一個靜態屬性property本質就是實現了__get__,__set__,__delete__三種方法。

propetry有兩種用法,第一種即:

class Foo:@property #靜態屬性def AAA(self):print('get的時候運行')@AAA.setterdef AAA(self,value):print('set的時候運行',value)@AAA.deleterdef AAA(self):print('delete的時候運行') f1 = Foo() f1.AAA f1.AAA='aaa' del f1.AAA

執行結果為:

get的時候運行 set的時候運行 aaa delete的時候運行

上述代碼中只有在屬性AAA定義property后才能定義AAA.setter,AAA.deleter。

第二種用法的代碼實現如下:

class Foo:def get_AAA(self):print('get的時候運行')def set_AAA(self,value):print('set的時候運行',value)def del_AAA(self):print('delete的時候運行')AAA = property(get_AAA,set_AAA,del_AAA) #內置property三個參數與get,set,delete一一對應 f1 = Foo() f1.AAA f1.AAA='aaa' del f1.AAA

執行結果為:

get的時候運行 set的時候運行 aaa delete的時候運行

上述兩種用法的結果都是一樣的。

我們也可以利用描述符自定制property,實現延時計算。我們先對一段代碼進行分析,來看看我們利用描述符自定制property該如何實現相同的目的。即:

class Room:def __init__(self,name,width,length):self.name = nameself.width = widthself.length = length@property #area=property(area)def area(self):return self.width*self.length r1 = Room('別墅',15,16) print(r1.area) #結果為:240

在上述代碼中@property相當于實現了area=property(area),而property它是一個類,這是不是相當于property類定義成Room類的類屬性,這不就是描述符的性質嗎?它既然是描述符,那么它是數據描述符還是非數據描述符呢?從結果它打印實例屬性可以看出,它是非數據描述符,因為實例屬性的優先級>非數據描述符。假如我們自定制property,不采用內置的靜態屬性property,該如何實現上述代碼,即:

class Lazyproperty:def __init__(self,func):self.func = funcdef __get__(self, instance, owner):return self.func(instance) #instance實例本身 class Room:def __init__(self,name,width,length):self.name = nameself.width = widthself.length = length@Lazyproperty #area=Lazyproperty(area)def area(self):return self.width*self.length r1 = Room('別墅',15,16) print(r1.area) #結果為:240

上述代碼中的@Lazyproperty是我自定制的,當然Lazyproperty類中我們只能定義成非數據描述符,否則不會執行area方法。

我們繼續利用自定制property來實現延時計算功能:

class Lazyproperty:def __init__(self,func):self.func = funcdef __get__(self, instance, owner):print('get')if instance is None: #被類調用必須寫,否則報錯,因為類沒有實例return selfres = self.func(instance) #instance實例本身setattr(instance,self.func.__name__,res) #緩存return res class Room:def __init__(self,name,width,length):self.name = nameself.width = widthself.length = length@Lazyproperty #area=Lazyproperty(area)def area(self):return self.width*self.length r1 = Room('別墅',15,16) print(r1.area) #從字典里先找,因為實例屬性>非數據描述符,沒有再去類的中找,然后出發了area的__get__方法 print(r1.area) #先從自己的屬性字典找,找到了,是上次計算的結果,這樣就不用每執行一次都去計算

上述代碼實現了延時計算功能,這樣這不會每次都打印get的操作。描述符是可以實現大部分python類特性中的底層魔法,包括@classmethod,@staticmethd,@property甚至是__slots__屬性。

?6.類的裝飾器

類的裝飾器與函數的裝飾器性質是一樣的,類的裝飾器分為無參裝飾器和有參裝飾器。

我們先來定義一個無參的裝飾器,即:

def deco(func):print('============')func.x = 1func.y = 2return func @deco #相當于Foo = deco(Foo) class Foo:pass print(Foo.__dict__)

執行結果為:

============ {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None, 'x': 1, 'y': 2}

上述代碼當程序遇到@deco就馬上執行了Foo=deco(Foo),可以在結果可以看出Foo類中的屬性字典中有鍵值對x與y。

下面我們來介紹有參的裝飾器該如何定義:

def Typed(**kwargs):def deco(obj):for key,val in kwargs.items():setattr(obj,key,val)return objreturn deco@Typed(x=1,y=2,z=3) #1.Typed(x=1,y=2,z=3)--->deco 2.@deco----->Foo=deco(Foo) class Foo:pass print(Foo.__dict__)@Typed(name='alex') #@deco---->Bar=deco(Bar) class Bar:pass print(Bar.name)

執行的結果為:

{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None, 'x': 1, 'y': 2, 'z': 3} alex

上述代碼定義了有參的裝飾器,函數Typed是用來接收所有參數的。

下面我們利用裝飾器的應用以及描述符來實現參數的賦值類型限制,即:

class Typed:def __init__(self,key,expected_type):self.key = keyself.expected_type = expected_typedef __get__(self, instance, owner):print('get方法')return instance.__dict__[self.key]def __set__(self, instance, value):print('set方法')if not isinstance(value,self.expected_type):raise TypeError('你傳入的類型不是%s' %self.expected_type)instance.__dict__[self.key] = valuedef __delete__(self, instance):print('delete方法')instance.__dict__.pop(self.key)def deco(**kwargs):def wrapper(obj):for key,val in kwargs.items():setattr(obj,key,Typed(key,val)) #Typed(key,val)描述符return objreturn wrapper@deco(name = str,age = int,salary = float) class People:def __init__(self,name,age,salary):self.name = nameself.age = ageself.salary = salaryp1 = People('alex',20,6666.66)

實例化時觸發了三次__set__方法。在描述符里也規定了參數的賦值類型。

轉載于:https://www.cnblogs.com/lzc69/p/11316469.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的描述符的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美日韩一区二区中文字幕 | 日韩精品在线免费看 | 东京av在线 | freesexvideos第一次 | 国产精品一区二区三区四区五区 | 98视频在线 | av无码精品一区二区三区宅噜噜 | 国产精品主播 | 日日夜夜精品免费视频 | 8x8ⅹ8成人免费视频观看 | 日本肉体xxxx裸体xxx免费 | 高清免费av | 少妇情理伦片丰满午夜在线观看 | 国产91在线免费 | 操你啦影院 | 国语对白一区二区三区 | 中文字幕精品在线视频 | 一级性爱视频 | 亚洲免费一区视频 | 亚洲插| 日本久久99 | 国产精品久久久久久久毛片 | 四虎国产 | 视频在线不卡 | 东京热加勒比无码少妇 | 免费网站观看www在线观看 | 久久久久99精品 | www.成人 | 日韩欧美国产亚洲 | 国产黄视频在线观看 | 蜜桃精品一区二区 | 99re在线播放 | 另类捆绑调教少妇 | 婷婷一区二区三区四区 | 韩国女主播一区二区 | 在线看片你懂的 | 九草在线视频 | 欧美激情片在线观看 | 那里可以看毛片 | 天天摸天天操 | 亚洲免费一区视频 | 久操福利在线 | 久在操 | 精品国产aⅴ一区二区三区东京热 | 天天干夜夜嗨 | 欧美老少做受xxxx高潮 | 精品一区中文字幕 | 欧美大屁股熟妇bbbbbb | 久久久亚洲成人 | 亚洲精品视频播放 | 欧美久久久久久久久中文字幕 | 天堂91| 日韩片在线观看 | 午夜精品久久久久久久久久久久 | 三级全黄做爰龚玥菲在线 | 超91在线 | 长河落日电视连续剧免费观看01 | 草逼免费视频 | 日本视频网站在线观看 | 天天干导航 | 看黄色一级片 | 天天艹日日干 | 3d成人动漫在线观看 | 日韩字幕在线观看 | 色欲久久久天天天综合网 | 最新天堂av | 亚洲 激情 | 成人在线视屏 | av片网站| 一区欧美 | 91官网在线观看 | 182av| 九九九九色 | 青青操免费在线视频 | 欧美日韩高清一区 | 大尺度做爰无遮挡露器官 | 亚洲综合在线五月 | 在线播放亚洲 | 国产成人毛毛毛片 | 处破痛哭a√18成年片免费 | 国产免费一区视频观看免费 | ass日本粉嫩pics珍品 | 色悠悠国产精品 | 毛片一区二区 | 欧美日p视频 | 黄色国产在线播放 | 69xxx国产| 琪琪秋霞午夜被窝电影网 | 性色在线| 99re6在线 | 五月激情五月婷婷 | 91精品国产日韩91久久久久久 | 91麻豆成人精品国产免费网站 | 少妇无码一区二区三区免费 | 成人在线高清 | 一区二区三区在线免费 | 中国美女一级黄色片 | 在线观看av资源 | 色av一区二区 |