python 惰性属性_python对象属性惰性取值

python面向对象进阶

在知乎上面看到这个如何让python对象属性具有惰性求值的能力,认真学习了一番,记录一下。

__setattr__、__getattr__、__delattr__

class Computer(object):

def __init__(self, brand, type):

self.brand = brand

self.type = type

# def __getattribute__(self, item):

# print("----> reference getattribute begin")

# super(Computer, self).__getattribute__(item)

def __getattr__(self, item):

print("----> reference getattr begin")

print("item: {0}".format(item))

if item in self.__dict__:

return self.__dict__[item]

else:

raise Exception("no attr {0}".format(item))

def __setattr__(self, key, value):

print("----> reference setattr begin")

print("***key: {0}, value: {1}***".format(key, value))

self.__dict__[key] = value

def __delattr__(self, item):

print("----> reference delattr begin")

self.__dict__.pop(item)

print("----> delattr end")

pc_1 = Computer('thinkpad', "i7")

# print(pc_1.__dict__)

print(pc_1.brand)

# print(pc_1.bran)

pc_1.size = "15.6"

print(pc_1.size)

# 实例化执行init方法,使用点号赋值时会调用__setattr__方法, 不重写这个方法会默认调用父类:父类会执行类似self.__dict__[key] = value

# pc_1.brand 会先直接执行__getattribute__,如果__getattribute__找不到而当前对象有__getattr__方法会去执行__getattr__去找,找不到就返回了

# pc_1.bran, 会首先执行__getattribute__, 如果__getattribute__找不到而当前对象有__getattr__方法会去执行__getattr__去找,找不到就返回了

# 当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError, 也就是说__getattr__只有在使用点调用属性且属性不存在的时候才会触发

__set__、__get__、__del__

# 描述符Str

class Str:

def __get__(self, instance, owner):

print('Str调用')

def __set__(self, instance, value):

print('Str设置...')

def __delete__(self, instance):

print('Str删除...')

class People(object):

name = Str()

def __init__(self, name, age): # name被Str类代理

self.name = name

self.age = age

p1 = People('tony', 18)

# 如果描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操作,于p1本身无关了,相当于覆盖了实例的属性

p1.name = 'tonyj'

print(p1.name)

# 实例的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了

print(p1.__dict__)

del p1.name

利用描述符让类的属性具有惰性求值:

class lazyproperty(object):

def __init__(self, fun):

print("1111111")

self.fun = fun

def __get__(self, instance, owner):

print("instance : {0}, owner: {1}".format(instance, owner))

if instance is None:

return self

value = self.fun(instance)

print("func: {0}, funcname: {1}".format(self.fun, self.fun.__name__))

setattr(instance, self.fun.__name__, value)

return value

class Circle:

area = 222

def __init__(self, radius):

self.radius = radius

@lazyproperty

def area(self):

print('Computing area')

return 3.1415 * self.radius ** 2

c = Circle(5)

print(c.__dict__)

print(c.area)

print(c.__dict__)

print(c.area)

# 个人分析: c.area语法首先会去对象属性里去查找,有则返回没有则继续,因为area已经被装饰器装饰,

# 其实c.area是调用c.lazyproperty(area),又因为lazyproperty是一个类,这时lazyproperty就相当于

# 对象c的一个代理类,这时会触发代理类的__get__方法__get__(self, instance, owner)

# 这里instance就是被代理类的实例,owner就是被代理的类,这里__get__里代码逻辑就是 这里

# value = self.func(instance)执行原函数内容,然后给instance设置值

# setattr(instance, self.fun.__name__, value),这样之后调用c.area时对象c的属性里就已经存在area属性了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值