#.get,getattr,__getattribute__的区别
# coding=gbk
# __get__、__getattr__、__getattribute都是访问属性的方法
# 有类A,a是A的实例,调用a.x的顺序
# 1、重载了__getattribute__,则调用
# 2、a.__dict__, 实例中是不允许有descriptor的,所以不会遇到descriptor
# A.__dict__, 也即a.__class__.__dict__ .如果遇到了descriptor,优先调用descriptor.
# 3、沿着继承链搜索父类.搜索a.__class__.__bases__中的所有__dict__. 如果有多重继承且是菱形继承的情况,按MRO(Method Resolution Order)顺序搜索
# 4、抛出AttributeError异常
class C():
a = '123'
def __setattr__(self, name, value):
print("__setattr__ called:", name, value)
object.__setattr__(self, name, value)
def __getattr__(self, name):
print("__getattr__ called:", name)
return name + " from getattr"
def __getattribute__(self, name):
print("__getattribute__ called:", name)
return object.__getattribute__(self, name)
def __get__(self, instance, owner):
print("__get__() is called", instance, owner)
return self
# c = C()
# c.x = '12'
# print(c.__dict__['x'])
# print(c.x)
# print(c.y) # 会调用__getattr__
# __getattr__(self, name):一般位置找不到attribute的时候,会调用
# __getattribute__(self, name):无条件被调用,除非引发异常,会调用__getattr__
# __get__(self, instance, owner) 如果class定义了它,则这个class就可以称为descriptor。
# owner是所有者的类,instance是访问descriptor的实例,如果不是通过实例访问,而是通过类访问的话,instance则为None。
# descriptor的实例自己访问自己是不会触发__get__,而会触发__call__,只有descriptor作为其它类的属性才有意义
class SubC():
d = C()
cc = SubC()
# print(cc.d)
# print(cc.d.a)
# print(cc.d.b)
# print(SubC.d) # 此时的instance是None
# print(SubC.d.a)
# print(SubC.d.b)
# 订单中商品的类
# 处理属性的内置函数
# __class__ 对象所属类的引用
# __dict__ 存储对象或者类的可写属性
# __slots__ 字符创组成的元组,指明允许的属性
# dir([object]) 列出对象的大多数属性
# getattr(object, name[, default]) 从object对象中获取name字符串对应的属性
# hasattr(object, name) 如果object对象中存在指定的属性,或者能以某种方式(例如继承)通过object对象获取指定的属性,返回True
# setattr(object, name, value) 把object对象指定属性的值设为value,前提是object对象能接受那个值
# vars([object]) 返回object对象的__dict__属性
# 处理属性的特殊方法
# __delattr__(self, name) 只要使用del语句删除属性,就会调用这个方法
# __dir__(self) 把对象传给dir函数时调用,列出属性
# __getattr__(self, name) 仅当获取指定的属性失败,搜索过obj、Class和超类之后调用
# __getattribute__(self, name) 尝试获取指定的属性时总会调用这个方法
# __setattr__(self, name, value) 尝试设置指定的属性时总会调用这个方法
# 数量可能为负
class LineItem:
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
# 把数据属性换成特性
class LineItem2:
def __init__(self, description, weight, price):
self.description = description
self.__weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
@property
def weight(self):
return self.__weight
@weight.setter
def weight(self, value):
if value > 0:
self.__weight = value
else:
raise ValueError('value must be > 0')
class LineItem2_2: # 不使用装饰器
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
def get_weight(self):
return self.__weight
def set_weight(self, value):
if value > 0:
self.__weight = value
else:
raise ValueError('value must be > 0')
weight = property(get_weight, set_weight)
def quantity(storage_name):
def qty_getter(instance): # property内部参数的函数第一个参数是self,这里是类
#print('instance_get', storage_name, instance)
return instance.__dict__[storage_name]
def qty_setter(instance, value):
#print('instance_set', storage_name, instance)
if value > 0:
instance.__dict__[storage_name] = value
else:
raise ValueError('value must be > 0')
return property(qty_getter, qty_setter)
class LineItem2_3: # 定义特性工厂函数
weight = quantity('weight')
price = quantity('price')
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
nutmeg = LineItem2_3('Moluccan nutmeg', 8, 13.95)
#print(nutmeg.weight, nutmeg.price)