拦截Python 2.3旧式mixin类中的__getattr__?

时间:2016-11-07 11:01:43

标签: python inheritance

我有一个基于Python 2.3的大型安装,具有200k LOC。作为迁移项目的一部分,我需要拦截所有旧式类的所有属性查找。

旧遗留代码:

class Foo(Bar):
    ...

我的想法是注入一个像

这样的常见mixin类
class Foo(Bar, Mixin):
    ...

class Mixin:

    def __getattr__(self, k)
        print repr(self), k
        return Foo.__getattr__(self, k)

然而,由于Foo.__getattr__解析,我总是在递归中运行 到Mixin.__getattr__

有没有办法修复Python 2.3旧式类的代码?

2 个答案:

答案 0 :(得分:0)

如果您已经注入mixins,为什么不将object添加为父级,以使其成为新风格

class Foo(Mixin, Bar, object):
    ...

然后使用super

class Mixin(object):

    def __getattr__(self, k)
        print repr(self), k
        return super(Mixin, self).__getattr__(k)

答案 1 :(得分:0)

假设您的代码库中没有类实现__setattr____getattr__,那么一种方法是在您的Mixin中拦截__setattr__,将值写入另一个保留属性,然后读取它回到__getattr__

class Mixin:
    def __setattr__(self, attr, value):
        # write the value into some special reserved space
        namespace = self.__dict__.setdefault("_namespace", {})
        namespace[attr] = value

    def __getattr__(self, attr):
        # reject special methods so e.g. __repr__ can't recurse
        if attr.startswith("__") and attr.endswith("__"):
            raise AttributeError

        # do whatever you wish to do here ...
        print repr(self), attr

        # read the value from the reserved space
        namespace = self.__dict__.get("_namespace", {})
        return namespace[attr]

示例:

class Foo(Mixin):
    def __init__(self):
        self.x = 1

然后

>>> Foo().x
<__main__.Foo instance at 0x10c4dad88> x

显然,如果您的Foo个类自己实现__setattr____getattr__,这将无效。