Day 23:python 面向对象 【装饰器,property应用,元类】

类的装饰器

的基本原理和 函数的装饰器原理基本一致

例:

def test(obj):
    print("====>>",obj)#obj就是Foo.那我们可以对这个类进行操作
    obj.x= 3
    obj.y =4
    return obj
@test # Foo = test(Foo)
class Foo:
    pass
print(Foo.__dict__)#属性字典里面就有我们设置的值
类的装饰器原理

上面说的是直接赋值,装装饰器写死了。但是如果这个装饰器用运用于多个类呢?参数不确定呢?

def test(**kwargs):
  #kwargs 就是test传进来的字典
    def deco(obj): #obj就是Foo.那我们可以对这个类进行操作
        for key,val in kwargs.items():
        #循环这个字典,得到key,val
            setattr(obj,key,val)
            #设置值到foo
        return obj 
    return deco
@test(name = "sjc",age = "28")#加括号就是运行了
#@test --->把字典传进去,并执行,变成@deco ,Foo = deco(Foo)
class Foo:
    pass
print(Foo.__dict__)
进阶

类的装饰器的应用

class Typed:
    def __init__(self,key,e_type):
        self.key = key
        self.e_type = e_type
    def __get__(self, instance, owner):
        return instance.__dict__[self.key]
    def __set__(self, instance,value,):
        if not isinstance(value,self.e_type):
            raise TypeError("你传入的%s不是%s" %(value,self.e_type))
        instance.__dict__[self.key] = value
def test(**kwargs):
    def deco(obj):
        for key,val in kwargs.items():
            setattr(obj,key,Typed(key,val))
            # setattr(Salary,name,Teped(name,str))
            #Type(key,val) 就是在调用描述符了。和下面对应
        return obj
    return deco
@test(name = str,age = int,salarty = float)
#如果Salary的参数过多,为了减少重复代码。
#取代name = Typed("name",str)
class Salary:
    # name = Typed("name",str)
    # age = Typed("age",int)
    # salarty = Typed("salarty",float)
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.salarty = salary
s1 = Salary("sunjinchao",12,2.3,)
print(s1.__dict__)
装饰器应用与描述符结合,检测输入类型

装饰器,也可以是个类! 

class lproperty:
    def __init__(self,func):
        self.func=func#func就是[gongzi]
    def __get__(self, instance, owner):
        return self.func(instance)
        #instance实例本身 S1
    def __set__(self, instance, value):
        pass
class Salary:
    # gongzi = lproperty(gongzi)
    def __init__(self,name,salary,kpi):
        self.name = name
        self.salarty = salary
        self.kpi = kpi
    @property#隐藏方法,然后调用的时候好像在调用数据属性。
    #gongzi = property(gongzi) // 就是增加描述符的操作
    #
    #property(gongzi) 实例化的过程 --》实例化就会触发init方法
    def gongzi(self):
        return self.salarty +self.kpi
s1 = Salary("sunjinchao",500,800)
print(s1.gongzi)#1300
#r1.gongzi.func(r1)
利用描述符模拟property

用自定制的property 实现 延迟计算功能(计算一次,存在缓存中下次直接使用,不用在触发函数运行)

class lproperty:
    def __init__(self,func):
        self.func=func#func就是[gongzi]
    def __get__(self, instance, owner):
        ret = self.func(instance)
        setattr(instance,self.func.__name__,ret)
        #直接把值设置在 r1实例的属性字典。
        #下次调用直接从字典里面找
        return ret
        #instance实例本身 S1
class Salary:
    # gongzi = lproperty(gongzi)
    def __init__(self,name,salary,kpi):
        self.name = name
        self.salarty = salary
        self.kpi = kpi
    @property#隐藏方法,然后调用的时候好像在调用数据属性。
    #gongzi = property(gongzi) // 就是增加描述符的操作
    #
    #property(gongzi) 实例化的过程 --》实例化就会触发init方法
    def gongzi(self):
        return self.salarty +self.kpi
s1 = Salary("sunjinchao",500,800)
print(s1.gongzi)#1300
#r1.gongzi.func(r1)
延迟计算

那如果给gongzi 这个函数属性设置值呢?

class Goods:
    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8
    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price
    @price.setter
    def price(self, value):
        self.original_price = value
    @price.deleter
    def price(self):
        del self.original_price
obj = Goods()
obj.price         # 获取商品价格
obj.price = 200   # 修改商品原价
print(obj.price)
del obj.price     # 删除商品原价
property 的函数属性设置值

元类 :metaclass

元类:元类就是类的类,是类的末班

元类是来控制如何创建类的,正如类是创建对象的模板一样

元类的实例 就是类,正如类的实例是一个对象,(f1,是foo的对象,那foo类是type的一个实例)

type是python的一个内建元类,用来控制生成类,python中,任何class定义的类其实都是type类实例化的对象

class foo:
    def __init__(self):
        pass
f1 = foo()
# print(type(f1))#<class '__main__.foo'>
# print(type(foo))#<class 'type'>
print(foo.__dict__)

def __init__(self,name):
    self.name = name
FFo = type('FFo',(object,),{'x':1,__init__:__init__})
#object新式类,有逗号,可以继承多个类
#设置数据属性,与 init方法
print(FFo.__dict__)
初识元类

 

 

posted on 2021-02-09 21:24  超nmmmmm  阅读(78)  评论(0编辑  收藏  举报

导航