最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python基礎(chǔ)詳解之描述符

 更新時(shí)間:2021年04月28日 16:14:02   作者:思想流浪者  
這篇文章主要介紹了Python基礎(chǔ)詳解之描述符,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下

一、描述符定義

描述符是一種類,我們把實(shí)現(xiàn)了__get__()、__set__()和__delete__()中的其中任意一種方法的類稱之為描述符。

描述符的作用是用來(lái)代理一個(gè)類的屬性,需要注意的是描述符不能定義在被使用類的構(gòu)造函數(shù)中,只能定義為類的屬性,它只屬于類的,不屬于實(shí)例,我們可以通過(guò)查看實(shí)例和類的字典來(lái)確認(rèn)這一點(diǎn)。

描述符是實(shí)現(xiàn)大部分Python類特性中最底層的數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)手段,我們常使用的@classmethod、@staticmethd、@property、甚至是__slots__等屬性都是通過(guò)描述符來(lái)實(shí)現(xiàn)的。它是很多高級(jí)庫(kù)和框架的重要工具之一,是使用到裝飾器或者元類的大型框架中的一個(gè)非常重要組件。

如下示例一個(gè)描述符及引用描述符類的代碼:

class Descriptors:
 
    def __init__(self, key, value_type):
        self.key = key
        self.value_type = value_type
 
    def __get__(self, instance, owner):
        print("===> 執(zhí)行Descriptors的 get")
        return instance.__dict__[self.key]
 
    def __set__(self, instance, value):
        print("===> 執(zhí)行Descriptors的 set")
        if not isinstance(value, self.value_type):
            raise TypeError("參數(shù)%s必須為%s" % (self.key, self.value_type))
        instance.__dict__[self.key] = value
 
    def __delete__(self, instance):
        print("===>  執(zhí)行Descriptors的delete")
        instance.__dict__.pop(self.key)
 
 
class Person:
    name = Descriptors("name", str)
    age = Descriptors("age", int)
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
 
person = Person("xu", 15)
print(person.__dict__)
person.name
person.name = "xu-1"
print(person.__dict__)
# 結(jié)果:
#     ===> 執(zhí)行Descriptors的 set
#     ===> 執(zhí)行Descriptors的 set
#     {'name': 'xu', 'age': 15}
#     ===> 執(zhí)行Descriptors的 get
#     ===> 執(zhí)行Descriptors的 set
#     {'name': 'xu-1', 'age': 15}

其中,Descriptors類就是一個(gè)描述符,Person是使用描述符的類。

類的__dict__屬性是類的一個(gè)內(nèi)置屬性,類的靜態(tài)函數(shù)、類函數(shù)、普通函數(shù)、全局變量以及一些內(nèi)置的屬性都是放在類__dict__里。

在輸出描述符的變量時(shí),會(huì)調(diào)用描述符中的__get__方法,在設(shè)置描述符變量時(shí),會(huì)調(diào)用描述符中的__set__方法。

二、描述符的種類和優(yōu)先級(jí)

描述符分為數(shù)據(jù)描述符和非數(shù)據(jù)描述符。

至少實(shí)現(xiàn)了內(nèi)置__set__()和__get__()方法的描述符稱為數(shù)據(jù)描述符;實(shí)現(xiàn)了除__set__()以外的方法的描述符稱為非數(shù)據(jù)描述符。

描述符的優(yōu)先級(jí)的高低順序:類屬性 > 數(shù)據(jù)描述符 > 實(shí)例屬性 > 非數(shù)據(jù)描述符 > 找不到的屬性觸發(fā)__getattr__()。

在上述“描述符定義”章節(jié)的例子中,實(shí)例person的屬性優(yōu)先級(jí)低于數(shù)據(jù)描述符Descriptors,所以在賦值或獲取值過(guò)程中,均調(diào)用了描述符的方法。

class Descriptors:
    def __get__(self, instance, owner):
        print("===> 執(zhí)行 Descriptors get")
 
    def __set__(self, instance, value):
        print("===> 執(zhí)行 Descriptors set")
 
    def __delete__(self, instance):
        print("===> 執(zhí)行 Descriptors delete")
 
 
class University:
    name = Descriptors()
 
    def __init__(self, name):
        self.name = name

類屬性 > 數(shù)據(jù)描述符

# 類屬性 > 數(shù)據(jù)描述符
# 在調(diào)用類屬性時(shí),原來(lái)字典中的數(shù)據(jù)描述法被覆蓋為 XX-XX
print(University.__dict__)  # {..., 'name': <__main__.Descriptors object at 0x7ff8c0eda278>,}
 
University.name = "XX-XX"
print(University.__dict__)  # {..., 'name': 'XX-XX',}

數(shù)據(jù)描述符 > 實(shí)例屬性

# 數(shù)據(jù)描述符 > 實(shí)例屬性
# 調(diào)用時(shí)會(huì)現(xiàn)在實(shí)例里面找,找不到name屬性,到類里面找,在類的字典里面找到 'name': <__main__.Descriptors object at 0x7fce16180a58>
# 初始化時(shí)調(diào)用 Descriptors 的 __set__; un.name 調(diào)用  __get__
print(University.__dict__)
un = University("xx-xx")
un.name
# 結(jié)果:
#     {..., 'name': <__main__.Descriptors object at 0x7ff8c0eda278>,}
#     ===> 執(zhí)行 Descriptors set
#     ===> 執(zhí)行 Descriptors get

下面是測(cè)試 實(shí)例屬性、 非數(shù)據(jù)描述符、__getattr__ 使用代碼

class Descriptors:
    def __get__(self, instance, owner):
        print("===>2 執(zhí)行 Descriptors get")
 
 
class University:
    name = Descriptors()
 
    def __init__(self, name):
        self.name = name
 
    def __getattr__(self, item):
        print("---> 查找 item = {}".format(item))

實(shí)例屬性 > 非數(shù)據(jù)描述符

# 實(shí)例屬性 > 非數(shù)據(jù)描述符
# 在創(chuàng)建實(shí)例的時(shí)候,會(huì)在屬性字典中添加 name,后面調(diào)用 un2.name 訪問(wèn),都是訪問(wèn)實(shí)例字典中的 name
un2 = University("xu2")
print(un2.name)  # xu    并沒(méi)有調(diào)用到  Descriptors 的 __get__
print(un2.__dict__)  # {'name': 'xu2'}
un2.name = "xu-2"
print(un2.__dict__)  # {'name': 'xu-2'}

非數(shù)據(jù)描述符 > 找不到的屬性觸發(fā)__getattr__

# 非數(shù)據(jù)描述符 > 找不到的屬性觸發(fā)__getattr__
# 找不到 name1 使用 __getattr__
un3 = University("xu3")
print(un3.name1)  # ---> 查找 item = name1

三、描述符的應(yīng)用

使用描述符檢驗(yàn)數(shù)據(jù)類型

class Typed:
    def __init__(self, key, type):
        self.key = key
        self.type = type
 
    def __get__(self, instance, owner):
        print("---> get 方法")
        # print("instance = {}, owner = {}".format(instance, owner))
        return instance.__dict__[self.key]
 
    def __set__(self, instance, value):
        print("---> set 方法")
        # print("instance = {}, value = {}".format(instance, value))
        if not isinstance(value, self.type):
            # print("設(shè)置name的值不是字符串: type = {}".format(type(value)))
            # return
            raise TypeError("設(shè)置{}的值不是{},當(dāng)前傳入數(shù)據(jù)的類型是{}".format(self.key, self.type, type(value)))
        instance.__dict__[self.key] = value
 
    def __delete__(self, instance):
        print("---> delete 方法")
        # print("instance = {}".format(instance))
        instance.__dict__.pop(self.key)
 
 
class Person:
    name = Typed("name", str)
    age = Typed("age", int)
 
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary
 
 
p1 = Person("xu", 99, 100.0)
print(p1.__dict__)
p1.name = "XU1"
print(p1.__dict__)
del p1.name
print(p1.__dict__)
# 結(jié)果:
#     ---> set 方法
#     ---> set 方法
#     {'name': 'xu', 'age': 99, 'salary': 100.0}
#     ---> set 方法
#     {'name': 'XU1', 'age': 99, 'salary': 100.0}
#     ---> delete 方法
#     {'age': 99, 'salary': 100.0}

四、描述符 + 類裝飾器  (給 Person類添加類屬性)

類裝飾器,道理和函數(shù)裝飾器一樣

def Typed(**kwargs):
    def deco(obj):
        for k, v in kwargs.items():
            setattr(obj, k, v)
        return obj
    return deco
 
 
@Typed(x=1, y=2)  # 1、Typed(x=1, y=2) ==> deco   2、@deco ==> Foo = deco(Foo)
class Foo:
    pass
 
 
# 通過(guò)類裝飾器給類添加屬性
print(Foo.__dict__)  # {......, 'x': 1, 'y': 2}
print(Foo.x)

使用描述符和類裝飾器給 Person類添加類屬性

"""
描述符 + 類裝飾器
"""
class Typed:
    def __init__(self, key, type):
        self.key = key
        self.type = type
 
    def __get__(self, instance, owner):
        print("---> get 方法")
        # print("instance = {}, owner = {}".format(instance, owner))
        return instance.__dict__[self.key]
 
    def __set__(self, instance, value):
        print("---> set 方法")
        # print("instance = {}, value = {}".format(instance, value))
        if not isinstance(value, self.type):
            # print("設(shè)置name的值不是字符串: type = {}".format(type(value)))
            # return
            raise TypeError("設(shè)置{}的值不是{},當(dāng)前傳入數(shù)據(jù)的類型是{}".format(self.key, self.type, type(value)))
        instance.__dict__[self.key] = value
 
    def __delete__(self, instance):
        print("---> delete 方法")
        # print("instance = {}".format(instance))
        instance.__dict__.pop(self.key)
 
 
def deco(**kwargs):
    def wrapper(obj):
        for k, v in kwargs.items():
            setattr(obj, k, Typed(k, v))
        return obj
    return wrapper
 
 
@deco(name=str, age=int)
class Person:
    # name = Typed("name", str)
    # age = Typed("age", int)
 
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary
 
 
p1 = Person("xu", 99, 100.0)
print(Person.__dict__)
print(p1.__dict__)
p1.name = "XU1"
print(p1.__dict__)
del p1.name
print(p1.__dict__)
# 結(jié)果:
#     ---> set 方法
#     ---> set 方法
#     {..., 'name': <__main__.Typed object at 0x7f3d79729dd8>, 'age': <__main__.Typed object at 0x7f3d79729e48>}
#     {'name': 'xu', 'age': 99, 'salary': 100.0}
#     ---> set 方法
#     {'name': 'XU1', 'age': 99, 'salary': 100.0}
#     ---> delete 方法
#     {'age': 99, 'salary': 100.0}

五、利用描述符自定義 @property

class Lazyproperty:
    def __init__(self, func):
        self.func = func
 
    def __get__(self, instance, owner):
        print("===> Lazypropertt.__get__ 參數(shù): instance = {}, owner = {}".format(instance, owner))
        if instance is None:
            return self
        res = self.func(instance)
        setattr(instance, self.func.__name__, res)
        return self.func(instance)
 
    # def __set__(self, instance, value):
    #     pass
 
 
class Room:
 
    def __init__(self, name, width, height):
        self.name = name
        self.width = width
        self.height = height
 
    # @property  # area=property(area)
    @Lazyproperty  # # area=Lazyproperty(area)
    def area(self):
        return self.width * self.height
 
#  @property 測(cè)試代碼
# r = Room("房間", 2, 3)
# print(Room.__dict__)  # {..., 'area': <property object at 0x7f8b42de5ea8>,}
# print(r.area)  # 6
 
# r2 = Room("房間2", 2, 3)
# print(r2.__dict__)  # {'name': '房間2', 'width': 2, 'height': 3}
# print(r2.area)
 
# print(Room.area)  # <__main__.Lazyproperty object at 0x7faabd589a58>
 
r3 = Room("房間3", 2, 3)
print(r3.area)
print(r3.area)
# 結(jié)果(只計(jì)算一次):
#     ===> Lazypropertt.__get__ 參數(shù): instance = <__main__.Room object at 0x7fd98e3757b8>, owner = <class '__main__.Room'>
#     6
#     6

六、property 補(bǔ)充

class Foo:
 
    @property
    def A(self):
        print("===> get A")
 
    @A.setter
    def A(self, val):
        print("===> set A, val = {}".format(val))
 
    @A.deleter
    def A(self):
        print("===> del A")
 
 
f = Foo()
f.A         # ===> get A
f.A = "a"   # ===> set A, val = a
del f.A     # ===> del A
 
 
 
class Foo:
 
    def get_A(self):
        print("===> get_A")
 
    def set_A(self, val):
        print("===> set_A, val = {}".format(val))
 
    def del_A(self):
        print("===> del_A")
 
    A = property(get_A, set_A, del_A)
 
 
f = Foo()
f.A         # ===> get_A
f.A = "a"   # ===> set_A, val = a
del f.A     # ===> del_A

到此這篇關(guān)于Python基礎(chǔ)詳解之描述符的文章就介紹到這了,更多相關(guān)Python描述符內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python時(shí)間管理黑科技之datetime函數(shù)詳解

    Python時(shí)間管理黑科技之datetime函數(shù)詳解

    在Python中,datetime模塊是處理日期和時(shí)間的標(biāo)準(zhǔn)庫(kù),它提供了一系列功能強(qiáng)大的函數(shù)和類,用于處理日期、時(shí)間、時(shí)間間隔等,本文將深入探討datetime模塊的使用方法,感興趣的可以了解下
    2023-08-08
  • TensorFlow:將ckpt文件固化成pb文件教程

    TensorFlow:將ckpt文件固化成pb文件教程

    今天小編就為大家分享一篇TensorFlow:將ckpt文件固化成pb文件教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-02
  • Python自動(dòng)化導(dǎo)出zabbix數(shù)據(jù)并發(fā)郵件腳本

    Python自動(dòng)化導(dǎo)出zabbix數(shù)據(jù)并發(fā)郵件腳本

    這篇文章主要介紹了Python自動(dòng)化導(dǎo)出zabbix數(shù)據(jù)并發(fā)郵件腳本,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • centos系統(tǒng)升級(jí)python 2.7.3

    centos系統(tǒng)升級(jí)python 2.7.3

    CentOS上安裝的python版本是2.6,不能滿足我運(yùn)行軟件的要求,所以對(duì)python進(jìn)行升級(jí)。Python的最新版本已經(jīng)是3.3,但是Python3的兼容性可能還有一定的問(wèn)題,所以還是升級(jí)到2.7較為保險(xiǎn)。
    2014-07-07
  • Python打造虎年祝福神器的示例代碼

    Python打造虎年祝福神器的示例代碼

    2022虎年將至,值此新春佳節(jié)之際,小編特地為大家介紹了一個(gè)利用Python實(shí)現(xiàn)的虎年祝福神器,文中的示例代碼講解詳細(xì),感興趣的可以動(dòng)手試一試
    2022-01-01
  • django 利用Q對(duì)象與F對(duì)象進(jìn)行查詢的實(shí)現(xiàn)

    django 利用Q對(duì)象與F對(duì)象進(jìn)行查詢的實(shí)現(xiàn)

    這篇文章主要介紹了django 利用Q對(duì)象與F對(duì)象進(jìn)行查詢的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-05-05
  • Python通過(guò)psd-tools解析PSD文件

    Python通過(guò)psd-tools解析PSD文件

    這篇文章主要介紹了Python通過(guò)psd-tools解析PSD文件,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-06-06
  • 在Python中使用poplib模塊收取郵件的教程

    在Python中使用poplib模塊收取郵件的教程

    這篇文章主要介紹了在Python中使用poplib模塊收取郵件的教程,代碼基于Python2.x版本,需要的朋友可以參考下
    2015-04-04
  • Python內(nèi)置函數(shù)bin() oct()等實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換

    Python內(nèi)置函數(shù)bin() oct()等實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換

    使用Python內(nèi)置函數(shù):bin()、oct()、int()、hex()可實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換;先看Python官方文檔中對(duì)這幾個(gè)內(nèi)置函數(shù)的描述,需要了解的朋友可以參考下
    2012-12-12
  • Python中執(zhí)行CMD命令的方法總結(jié)

    Python中執(zhí)行CMD命令的方法總結(jié)

    在實(shí)際開發(fā)中,有時(shí)候我們需要在Python中執(zhí)行一些系統(tǒng)命令(CMD命令),本文將詳細(xì)介紹在Python中執(zhí)行CMD命令的方法,并通過(guò)豐富的示例代碼幫助大家更全面地理解這一過(guò)程,希望對(duì)大家有所幫助
    2023-12-12

最新評(píng)論

波密县| 阳泉市| 涞源县| 东乌| 阿图什市| 南昌县| 恩施市| 出国| 方山县| 宣化县| 尚义县| 永登县| 万山特区| 天长市| 姚安县| 屏山县| 德惠市| 濮阳县| 湖北省| 祁门县| 辽宁省| 佛冈县| 亳州市| 大庆市| 定边县| 开原市| 会泽县| 大丰市| 崇阳县| 台南市| 仙游县| 乌兰浩特市| 措美县| 泰和县| 绵竹市| 民丰县| 云龙县| 堆龙德庆县| 朝阳市| 雷州市| 花莲县|