python——类的装饰器/元类

一、类的装饰器

装饰器并不是在调用该函数/对象的时候调用的,而是在代码编译的过程中已经返回函数/对象,当改函数/对象被调用的时候,调用的是已经返回的函数/对象

类作为一个对象,也可以被装饰。

——通过给类添加装饰器的方式,给类增加类属性

def wrap(obj):
    print("装饰器-----")
    obj.x = 1
    obj.y = 3
    obj.z = 5
    return obj
​
@wrap  #将Foo类作为一个参数传入装饰器函数wrap,返回同时返回该对象,把新对象重新命名为Foo
#即 Foo = wrap(Foo)
class Foo:
    pass

print(Foo.__dict__) #输出结果可以看到,新的Foo类新增了x,y,z属性
>>> 装饰器-----
>>> {'__module__': '__main__', '__init__': <function Foo3.__init__ at 0x0000029C089ABBF8>, '__dict__': <attribute '__dict__' of 'Foo3' objects>, '__weakref__': <attribute '__weakref__' of 'Foo3' objects>, '__doc__': None, 'x': 1, 'y': 3, 'z': 5}
​

函数可以作为一个对象,也有__dict__方法

def wrap(obj):
    print("装饰器-----")
    obj.x = 1
    obj.y = 3
    obj.z = 5
    return obj
​
@wrap #test = wrap(test)
def test():
    print("test-----")
test.x = 10  #test的x属性被重新赋值
print(test.__dict__) #输出结果可以看到,test作为一个函数也有__dict__方法,
# 新的test函数新增了x,y,z属性

>>>{'x': 10, 'y': 3, 'z': 5}

类的装饰器应用——通过给类加带参数的装饰器,给类增加一个类属性,该类属性是描述符类的实例对象

class Type:
​
    def __init__(self,key,except_type):  #People对象的key,和期望的数据类型
        self.key = key
        self.except_type = except_type
​
    def __get__(self, instance, owner):
        return isinstance.__dict__[self.key]
​
    def __set__(self, instance, value):
        print("instance---",instance)
        if not isinstance(value,self.except_type):
            print("您输入的类型不是%s"%self.except_type)
            raise TypeError
        instance.__dict__[self.key] = value
​
    def __delete__(self, instance):
        isinstance.__dict__.pop(self.key)
​
def deco(**kwargs):       ##这个装饰器的作用相当于给类添加了name=Type('name',str) age=Type('age',int)
    def wrapper(obj):      #类的装饰器
        for key,val in kwargs.items():
            setattr(obj,key,Type(key,val))  #设置people类对象的每个参数的描述符
        return obj
    return wrapper
​
@deco(name=str,age=int)
class People:
​
    def __init__(self,name,age):
        self.name = name
        self.age = age
​
​
if __name__=='__main__':
    print('start1')
    p = People("nick", 18)
    print(p.__dict__)
    print('start2')
    p1 = People("jerry", 20)
    print(p1.__dict__)
    print(p.__dict__)

#输出
______
start1
instance--- <__main__.People object at 0x000001BCBE39FD30>
instance--- <__main__.People object at 0x000001BCBE39FD30>
{'name': 'nick', 'age': 18}
start2
instance--- <__main__.People object at 0x000001BCBE39FB38>
instance--- <__main__.People object at 0x000001BCBE39FB38>
{'name': 'jerry', 'age': 20}
{'name': 'nick', 'age': 18}

 

二、自定义property

装饰器也可以是一个类,在自定义property中要使用一个类作为装饰器

class LazyProperty:

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

    def __get__(self, instance, owner):
        print("执行__get__")
        if not instance:  # 如果是用原类.属性来调用,,这时instance(对象)值为None,直接返回描述符对象
            return self
        res = self.func(instance)  # 执行传入的函数属性,并把原对象作为参数传入
        return res

class Room:

    def __init__(self, name, length, width):
        self.name = name
        self.length = length
        self.width = width

    @LazyProperty  # 这里相当于执行了area  = LazyProperty(area),这里的azyProperty(area)其实是非数据描述符,相当于给这个类新增了一个类属性,该类属性是数据描述符类LazyProperty的实例对象
    # 新的area已经是经过类LazyProperty装饰过的函数地址
    def area(self):
        return self.length * self.width

if __name__=='__main__':

    print(Room.__dict__)
    r = Room("nick", 18, 10)
    print(r.area)
    print(r.__dict__)
    print(Room.__dict__)

输出:
{'__module__': '__main__', '__init__': <function Room.__init__ at 0x0000024858FF6048>, 'area': <__main__.LazyProperty object at 0x0000024858F7F6A0>, '__dict__': <attribute '__dict__' of 'Room' objects>, '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}
执行__get__
180
{'name': 'nick', 'length': 18, 'width': 10}
{'__module__': '__main__', '__init__': <function Room.__init__ at 0x0000024858FF6048>, 'area': <__main__.LazyProperty object at 0x0000024858F7F6A0>, '__dict__': <attribute '__dict__' of 'Room' objects>, '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}
class LazyProperty:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        print("执行__get__")
        if not instance:  # 如果是用原类.属性来调用,这时instance(对象)值为None,直接返回描述符对象
            return self

        value = self.func(instance)  # 执行传入的函数属性,并把原对象作为参数传入
        setattr(instance,self.func.__name__,value) #将每次调用的函数属性名字和值存入对象的__dict__,相当于给instace(实例)新增实例属性area,由于LazyProperty是个非数据描述类,所有实例属性优先级更高
        # self.func.__name__是获取被调用函数属性的名字
        return value


class Room:
   def __init__(self, name, length, width):
        self.name = name
        self.length = length
        self.width = width
    @LazyProperty  # 这里相当于执行了area  = LazyProperty(area),这里的azyProperty(area)其实是非数据描述符,
    # 新的area已经是经过类LazyProperty装饰过的函数地址
    def area(self):
        return self.length * self.width

r = Room("nick", 18, 10)
print(r.__dict__)
print(r.area)
print(r.area)   #这里将不再调用__get__

setattr(instance,self.func.__name__,value) #将每次调用的函数属性名字和值存入对象的__dict__,相当于给instace(实例)新增实例属性area,由于LazyProperty是个非数据描述类,所有实例属性优先级更高。当第二次调用area时,调用实例属性而不是非数据描述类的__get__

 

三、property补充

一个静态属性property本质就是实现了get,set,delete三种方法

用语法糖可以实现property的类似属性的设置和删除,与一般的属性设置删除没有区别

class People:
​
    def __init__(self):
        self.study = "8h"
​
    @property
    def study(self):
        pr
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值