1.描述符的应用
用描述符实行类型检测
classDtype:def __init__(self,key,expect_type):
self.key=key
self.expect_type=expect_typedef __get__(self, instance, owner):return instance.__dict__[self.key]def __set__(self, instance, value):if notisinstance(value,self.expect_type):raise TypeError('%s传入的类型有误,应该为%s'%(self.key,self.expect_type))
instance.__dict__[self.key] =valuedef __delete__(self, instance):
instance.__dict__.pop[self.key]classPeople:
name= Dtype('name',str)
age= Dtype('age',int)def __init__(self,name,age):
self.name=name
self.age=age
p1= People('chris','18')print(p1.__dict__)
2.类的装饰器
def daju(**kwargs):defdeco(obj):for k,v inkwargs.items():
setattr(obj,k,v)returnobjreturndeco
@daju(x=1,y=2) #先运行daju(x=1,y=2) 返回一个deco 相当于@deco Foo=deco(Foo)
classFoo:pass
print(Foo.__dict__)
此时实现了 对类的修饰 加入了x,y的属性
加入对类型的限制:
classTyped:def __init__(self,key,expect_type):
self.key=key
self.expect_type=expect_typedef __set__(self, instance, value):if notisinstance(value,self.expect_type):raise TypeError('%s输入的类型有误,应为%s类型' %(self.key,self.expect_type))
instance.__dict__[self.key] =valuedef deco(**kwargs): #kwargs 接收到 {'name' = str, 'age' = int, 'salary' = float}
defwrapper(obj):for k,v inkwargs.items():print(k,v)
setattr(obj,k,Typed(k,v))#设置值时,将K给描述符代理 实现类型限制 既name = Typed('name',str)
#setattr(Foo,'name',Typed('name',str)) 上面相当于执行这个 Foo.name = Typed('name',str)
returnobjreturnwrapper
@deco(name= str, age = int, salary = float) #装饰器代替了三个重复的代码 实现给Foo类设定属性 只不过这个属性是描述符 对类的类型实现限制
classFoo:#name = Typed('name',str)
#age = Typed('age',int)
#salary = Typed('salary',str)
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary
p1= Foo('chris',19,25.7)print(Foo.__dict__)print(p1.__dict__)
3.利用描述符自定制property
classLazyproperty:def __init__(self,func):
self.func=func#print('22222')
def __get__(self, instance, owner): #实例调用时instance是实例自己 owner 为其所在的类 类调用时instance 为 None owner为类自己
if instance isNone:returnself
val=self.func(instance)returnvalclassRoom:def __init__(self,name,length,width):
self.name=name
self.length=length
self.width=width
@Lazyproperty#area = Lazyproperpy(area) 也是在增加描述符
defarea(self):return self.length *self.width
r1= Room('厕所',18,23)print(Room.area)
print(r1.area)
print(r1.area)
print(r1.area)
!!!此时实例调用area方法时会触发get方法,get方法中会自动将area算出来的值保存在实例的字典中,又因为Lazyproperty为非数据描述符,优先级低于实例属性,所以下次调用area方法时,会优先从实例属性字典中查找,所以不会触发get方法
4.自定制property功能实现延迟计算功能:定义set方法使描述符成为数据描述符,因此每次调用时都会从数据描述符中调用get方法
importtimeclassLazyproperty:def __init__(self,func):
self.func=func#print('22222')
def __get__(self, instance, owner): #实例调用时instance是实例自己 owner 为其所在的类 类调用时instance 为 None owner为类自己
time.sleep(2)print('get方法')if instance isNone:returnself
val=self.func(instance)
setattr(instance,self.func.__name__,val) #将area算出来的结果存放到实例自己的属性名为area的字典当中
returnvaldef __set__(self, instance, value):pass
classRoom:def __init__(self,name,length,width):
self.name=name
self.length=length
self.width=width
@Lazyproperty#area = Lazyproperpy(area) 也是在增加描述符
defarea(self):return self.length *self.width
r1= Room('厕所',18,23)print(r1.area)print(r1.area)print(r1.area)
5.利用描述符自定制一个classmethod
classClassMethod:def __init__(self,func):
self.func=funcdef __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
def feedback(*args,**kwargs):print('在这里可以加功能啊...')return self.func(owner,*args,**kwargs)returnfeedbackclassPeople:
name='linhaifeng'@ClassMethod#say_hi=ClassMethod(say_hi)
defsay_hi(cls,msg):print('你好啊,帅哥 %s %s' %(cls.name,msg))
People.say_hi('你是那偷心的贼')
p1=People()
p1.say_hi('你是那偷心的贼')
6.property补充 为静态属性设置值时用的。setter方法 删除静态属性值时 用.deleter方法
classFoo:
@propertydefAAA(self):print('get的时候运行我啊')
@AAA.setterdefAAA(self,value):print('set的时候运行我啊')
@AAA.deleterdefAAA(self):print('delete的时候运行我啊')#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
或者
lassFoo:
defget_AAA(self):
print('get的时候运行我啊')
defset_AAA(self,value):
print('set的时候运行我啊')
defdelete_AAA(self):
print('delete的时候运行我啊')
AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
应用场景如下:
classGoods:def __init__(self):#原价
self.original_price = 100
#折扣
self.discount = 0.8@propertydefprice(self):#实际价格 = 原价 * 折扣
new_price = self.original_price *self.discountreturnnew_price
@price.setterdefprice(self, value):
self.original_price=value
@price.deleterdefprice(self):delself.original_price
obj=Goods()
obj.price#获取商品价格
obj.price = 200 #修改商品原价
print(obj.price)del obj.price #删除商品原价
View Code
7.元类
元类是类的类,是类的模板,元类是用来控制如何创建类的,元类的实例是类,正如类的实例是对象
type是pyhton的一个内建元类,用来直接控制生成类
FFo = type('Foo',(object,),{'x':1}) #用type创建类 第一个参数为类名,第二个参数为继承的类,新式类默认加个object,第三个参数是属性
模拟元类帮你生成对象的过程:可以自己控制实例化的过程 定制自己的逻辑
classMytype(type):def __init__(self,a,b,c):print('这是我的元类')def __call__(self, *args, **kwargs):
obj= object.__new__(self) ##产生一个Foo的对象 self就是Foo
self.__init__(obj,*args,**kwargs) #为Foo生成的对象的字典里加属性
returnobjclass Foo(metaclass=Mytype): #相当于MYtype('Foo',(object),{}) 传过去四个参数
def __init__(self,name):
self.name=name
f1= Foo('chris') #相当于在执行Mytype的call方法