1. 程式人生 > >python之路(11)描述符

python之路(11)描述符

前言

  描述符是用於代理另一個類的屬性,一般用於大型的框架中,在實際的開發專案中較少使用,本質是一個實現了__get__(),__set__(),__delete__()其中一個方法的新式類

  __get__():呼叫一個屬性時執行

  __set__():屬性賦值時執行

  __delete__():採用del刪除屬性時觸發

  描述符實現@property

  描述符實現@classmethod

  描述符實現@staticmethod

 示例

#描述符
class test:
    def __get__(self, instance, owner):
        print('---get方法')

    def __set__(self, instance, value):
        print('---set方法')

    def __delete__(self, instance):
        print('---delete方法')

class test2:
    name = test()#描述符代理了test2類裡的name屬性

t1 = test2()
#呼叫了被描述符代理的屬性,執行__get__()方法
t1.name #---get方法
#賦值了被描述符代理的屬性,執行__set__()方法
t1.name = 1 #---set方法
#賦值了被描述符代理的屬性,執行__delete__()方法
del t1.name #---delete方法

 屬性查詢的優先順序

  1.類屬性

  2.資料描述符(同時實現了__get__()和__set__()方法)

  3.例項屬性

  4.非資料描述符(沒有實現__set__()方法)

  5.找不到的屬性執行__getattr__()

#非資料描述符
class test:
    def __get__(self, instance, owner):
        print('get方法')


class test2:
    name = test()#描述符代理了test2類裡的name屬性

t1 = test2()
#在例項物件裡中建立了name屬性,並賦值chen
t1.name 
= 'chen' print(t1.__dict__) #{'name': 'chen'}

利用描述符實現賦值型別限制(一)

#資料描述符
class Typed:
    def __init__(self,key,value_type):
        self.key = key
        self.value_type = value_type

    def __get__(self, instance, owner):
        print('get方法')
        return  instance.__dict__[self.key]

    def __set__(self, instance, value):
        print('set方法')
        if not isinstance(value,self.value_type): #判斷型別
            raise TypeError('傳入的型別不是',self.value_type)
        instance.__dict__[self.key] = value


    def __delete__(self, instance):
        print('delete方法')
        instance.__dict__.pop(self.key)


class People:
    name = Typed('name',str) #資料描述符代理屬性
    age = Typed('age',int) #資料描述符代理屬性

    def __init__(self,name,age):
        self.name = name #賦值操作,執行__set__方法
        self.age = age


#測試
p1 = People('chen',21)
print(p1.__dict__) #{'name': 'chen', 'age': 21}

p1 = People('chen','21') #報錯:TypeError: ('傳入的型別不是', <class 'int'>)

利用描述符和裝飾器實現賦值型別限制(二)

#資料描述符
class Typed:
    def __init__(self,key,value_type):
        self.key = key
        self.value_type = value_type

    def __get__(self, instance, owner):
        print('get方法')
        return  instance.__dict__[self.key]

    def __set__(self, instance, value):
        print('set方法')
        if not isinstance(value,self.value_type): #判斷型別
            raise TypeError('傳入的型別不是',self.value_type)
        instance.__dict__[self.key] = value


    def __delete__(self, instance):
        print('delete方法')
        instance.__dict__.pop(self.key)


#限制賦值型別的裝飾器
def deco(**kwargs):
    def warapper(obj):
        for key,val in kwargs.items():

            setattr(obj,key,Typed(key,val)) #在裝飾器中給類屬性實現描述符代理

        return obj
    return warapper


@deco(name=str,age=int) #@wrapper ===>People=wrapper(People)
class People:
    #使用裝飾器取代了以下兩步
    # name = Typed('name',str) #資料描述符代理屬性
    # age = Typed('age',int) #資料描述符代理屬性
    def __init__(self,name,age):
        self.name = name #賦值操作,執行__set__方法
        self.age = age


#測試
p1 = People('chen',21)
'''
輸出:
set方法
set方法
'''
print(p1.__dict__) #{'name': 'chen', 'age': 21}

 描述符實現@property

class Demoproperty:
    def __init__(self,func):
        print('----+')
        self.func = func


class People:
    def __init__(self,name,age):
        self.name = name #賦值操作,執行__set__方法
        self.age = age

    @Demoproperty #eat=Demoproperty(eat)
    def eat(self):
        print("%s在吃飯"%self.name)


p1 =People('chen',21)
p1.eat.func(p1) #chen在吃飯
瞎搞
#非資料描述符
class Demoproperty:
    def __init__(self,func):
        self.func = func

    def __get__(self, instance, owner):
        print('get')
        res = self.func(instance)
        return res

class People:
    
    def __init__(self,name,age):
        self.name = name #賦值操作,執行__set__方法
        self.age = age

    #實現了新增描述符的操作
    @Demoproperty #eat=Demoproperty(eat)
    def eat(self):
        print("%s在吃飯"%self.name)

p1 =People('chen',21)
p1.eat #chen在吃飯

 描述符實現@calssmethod

classmethod 修飾符對應的函式不需要例項化,不需要 self 引數,但第一個引數需要是表示自身類的 cls 引數,可以來呼叫類的屬性,類的方法,例項化物件等  

class ClassMethod:
    def __init__(self,func):
        self.func=func
    
    def __get__(self, instance, owner): #owner是類
        def feedback(*args,**kwargs):

            return self.func(owner,*args,**kwargs)

        return feedback #返回一個可以傳參的方法

class People:

    @ClassMethod # say_hi=ClassMethod(say_hi)
    def say_hi(cls,name,age):
        print('我是%s,年齡%s' %(name,age))

People.say_hi('chen',21) #我是chen,年齡21

描述符實現@staticmethod

class StaticMethod:
    def __init__(self,func):
        self.func=func

    def __get__(self, instance, owner): #owner是類
        def feedback(*args,**kwargs):

            return self.func(*args,**kwargs)

        return feedback #返回一個可以傳參的方法

class People:

    @StaticMethod # say_hi=ClassMethod(say_hi)
    def say_hi(name,age):
        print('我是%s,年齡%s' %(name,age))

People.say_hi('chen',21) #我是chen,年齡21