Python–常用模块脚本–__get__,__getattr__,__getattribute__的区别

#.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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柴寺仓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值