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 实现 延迟计算功能(计算一次,存在缓存中下次直接使用,不用在触发函数运行)
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 # 删除商品原价
元类 :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__)
人生苦短,我用Python