对非类属性使用Python的__get__描述符

时间:2018-12-28 11:40:24

标签: python class attributes python-descriptors

使用__get__描述符,我想实现以下目标:

class Wrapper:
    def __init__(self, wrapped_value):
        self._wrapped_value = wrapped_value

    def __get__(self, instance, owner):
        return self._wrapped_value

wrapper = Wrapper('foo')
assert type(wrapper) == type('foo')

原来,__get__描述符仅在Wrapper实例是其他类的类属性时才被调用,而在Wrapper实例是独立对象时,则不会被调用(不受任何class属性的约束。)

是否有一种方法可以使__get__描述符在非类属性中工作?

主要目标是实现包装器,该包装器在使用时就像包装值一样(我知道乍一看听起来没有用,但在某些用例中会有所帮助)。因此,也许有其他方法可以实现而不使用__get__描述符?

1 个答案:

答案 0 :(得分:1)

如果您希望Wrapper类控制对包装类属性的访问,则可以使用__getattr__魔术方法。

假设我们有一个Foo类:

class Foo(object):

    def bar(self):
        return 'bar'

    def baz(self):
        return 'baz'

假设我们正在与一些我们无法控制的代码进行交互,这些代码要求Foo.bar()的输出为大写,并且我们不想在代码中显式调用.upper()

我们可以创建一个包装类,以拦截对Foo.bar()的调用,但透明地允许访问Foo的其他方法(本质上是Adapter pattern)。

class Wrapper(object):

    def __init__(self, wrapped):
        self._wrapped = wrapped

    def __getattr__(self, name):
        # If 'name' isn't an attribute of this class,
        # get it from the wrapped instance.
        return getattr(self._wrapped, name)

    def bar(self):
        # Intercept calls to the wrapped instance's bar() method.
        return self._wrapped.bar().upper()



>>> wrapper = Wrapper(Foo())
>>> print wrapper.baz()
baz
>>> print wrapper.bar()
BAR

Footype检查不会将此Wrapper类报告为isinstance,但是只要调用,它就可以代替Foo使用代码依赖于duck-typing,而不是(非Python的)显式类型检查。

必须明确地完成诸如__str__之类的魔术方法的拦截。这是因为这些方法总是直接looked up直接在实例的类上,因此__getattr____getattribute__被绕过了。

因此要覆盖Foo.__str__,您需要执行以下操作:

class Foo(object):

    ...

    def __str__(self):
        return 'I am a Foo'


class Wrapper(object):

    ...

    def __str__(self):
        return str(self._wrapped)

>>> wrapper = Wrapper(Foo())
>>> print wrapper
I am a Foo