9.描述符 装饰器

2018-08-21  本文已影响4人  芝麻酱的简书

描述符:

描述符本质是一个新式类,在这个新式类中,至少出现了__get__()__set__()或者__delete__()方法中的一个,也被称为描述符协议。

描述符分为两种:

注意:对象本身调用不会触发描述符协议,当该新式类为别的类的属性,通过别的类来调用该新式类时候才会触发“

class Foo:
    def __set__(self, instance, value):
    # 可以通过__dict__属性字典设置,在设置前可以增加判断等操作
 
        print("hahaha")


class Tmp:
    #Foo()是数据描述符 代理了foo对象的属性调用相关方法
    foo = Foo()

result = Tmp()
result.foo = "asdf"

函数装饰器复习

前有函数装饰器:

def foo(func):
    print("装饰器")
    return func;

@foo   # 这一步就等于func1 = foo(func1)
def func1():
    print("func1")


func1()

类装饰器使用

终极代码:类装饰器 + 描述符

class TypedC:
    def __init__(self, key, classType):
        self.key = key
        self.classType = classType

    def __get__(self, instance, owner):
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        if not isinstance(value, self.classType):
            raise TypeError("传入的数据类型有问题")
        instance.__dict__[self.key] = value


def out_deco(**kwargs):
    def in_deco(obj):
        for key, value in kwargs.items():
            setattr(obj, key, TypedC(key,value))
        return obj
    return deco


@out_deco(name=str, age=int)
class New:

    def __init__(self, name, age):
        self.name = name
        self.age = age



print(New("alex",100).__dict__)

解释:

@out_deco(name=str, age=int)
先忽略@,即执行右半边方法: out_deco(name=str, age=int)  -> out_deco({字典}) 
得到:
@in_deco(New)   相当于   New = in_deco(New)

然后执行in_deco(New)内部循环:
setattr(obj, key, TypedC(key,value))  相当于  New.key = TypedC("name", str)




自定义装饰器

使用类装饰器 模拟系统@property的实现

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

    def __get__(self, instance, owner):
        return self.func(instance)


class Foo:
    def __init__(self):
        pass

    @Deco_class
    def showAnim(self):
        print("show anim 运行")

obj = Foo()
obj.showAnim

改进版:储存函数执行结果,下次不用重复计算执行

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

    # 因为没有重写__set__方法,所以是非数据描述符,优先级比实例属性低
    def __get__(self, instance, owner):

        res = self.func(instance)
        # 储存结果到实例对象中后 下次调用 由于优先级的问题  会优先从实例对象中查找showAnim方法,而不是调用非数据描述符
        setattr(instance, self.func.__name__, res)
        return res


class Foo:
    def __init__(self):
        pass

    @Deco_class
    def showAnim(self):
        print("show anim 运行")

obj = Foo()
obj.showAnim


补充:

使用@property装饰器修饰的方法,不可以赋值,需要:

class Foo:

    @property
    def showAnim(self):
        print("show anim 运行")

    @showAnim.setter
    def showAnim(self, name):
        print("show anim 运行", name)

obj = Foo()
obj.showAnim

obj.showAnim = "bill"

另一种写法:

class Foo:

    def get_a(self):
        print("get method")

    def set_a(self, val):
        print("set method")

    def del_a(self):
        print("del method")

    aaa = property(get_a, set_a, del_a)

obj = Foo()
obj.aaa = "bill"
上一篇 下一篇

猜你喜欢

热点阅读