python描述符应用_Python开发之路 - 描述符的应用

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方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值