系统学习Python——装饰器:“私有“和“公有“属性案例-[为Python3.X重定义运算符重载方法的途径:路由器、描述符、自动化]

本文探讨了如何改进Python中的混合类设计,特别是通过简化编程结构和使用描述符来减少内置操作的额外调用。两种变体展示了如何处理内置操作和属性访问控制,确保在Python2.X和3.X中的兼容性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分类目录:《系统学习Python》总目录


自然地,之前的文章中的两个混合器父类变体都可以通过代码的一些额外变化来改进。除了两个值得简要关注的变体外,这里我们将略过大部分。首先,下面比较第一个混合方案的变种一一其使用了更加简单的编程结构,但是这也导致每次内置操作都增加一次额外调用,使得它更慢(尽管在一个代理上下文中慢得不是很显著):

class BulitinsMixin:
    def reroute(self, attr, *args, **kagrs):
        return self.__calss__.__getattr__(self, attr)(*args, **kargs)
        
    def __add__(self, other):
        return self.reroute('__add__', other)
    
    def __str__(self):
        return self.reroute('__str__')
    
    def __getitem__(self, index):
        return self.reroute('__add__', index)
    
    def __call__(self, *args, **kargs):
        return self.reroute('__add__', *args, **kargs)
    
def accessControl(failIf):
    def onDecorator(aClass):
        class onInstance(BulitinsMixin):
            def __init__(self, *args, **kwags):
                self.__wrapped = aClass(*args, **kwags)
    
    def __str__(self):
        return str(self.__wrapped)
    
    def __add__(self, other):
        return self.__wrapped + other
    
    def __getitem__(self, index):
        return self.__wrapped[index]
    
    def __call__(self, *args, **kargs):
        return self.__wrapped(*args, **kargs)
    
    def __getattr__(self, attr):
        trace('get:', attr)
        if failIf(attr):
            raise TypeError('Private attribute fetch:' + attr)
        else:
            return getattr(self.__wrapped, attr)
                
     def __setattr__(self, attr, value):
        trace('set:', attr, value)
        f attr == '_onInstance__wrapped':
            self.__dict__[attr] = value
        elif failIf(attr):
            raise TypeError('Private attribute change:' + attr)
        else:
            setattr(self.__wrapped, attr, value)
        return onInstance
    return onDecorator

其次,所有前置的内置混合类显式地编写了每个运算符重载方法,并截获了由运算发出的调用。有了替代代码,我们就能够从一个名称表单中机械地生成方法,并且通过创建类级别的描述符来仅仅截获调用前的属性获取一一正如在下面的代码中所做的,就像第二个混合替代方案,其假设被代理的对象在代理实例自身中被命名为_wrapped

class BulitinsMixin:
    class ProxyDesc(object):
        def __init__(self, attrname):
            self.attrname = attrname
            
        def __get__(self, instance, owner):
            return getattr(instance.wrapped, self.attrname)
        
    builtins = ['add', 'str', 'getitem', 'call']
    for attr in builtins:
        exec('__%s__ = ProxyDesc("__%s__")' % (attr, attr))

这一编程方法可能是最为简洁的,但也可能是最为隐晦和复杂的。它通过共享名称与其子类相当紧密地耦合在一起。这个类中最后的循环等价于下面在混合类的局部作用域中运行的语句一一一它通过从__get__方法内的被包装对象获取属性,而不是捕获随后的操作调用自身,来创建响应初始名称查找的描述符:

__add__ = ProxyDesc('__add__')
__str__ = ProxyDesc('__str__')

通过内联或混合继承添加了这样的运算符重载方法后,前面使用__add____str__ 重载了+printPrivate示例客户端在Python2.X和Python3.X下都能正确地工作,重载了索引和调用的子类也一样工作。

参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

von Neumann

您的赞赏是我创作最大的动力~

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

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

打赏作者

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

抵扣说明:

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

余额充值