Если вы хотите, чтобы ваш класс Wrapper управлял доступом к атрибутам обернутых классов, вы можете использовать магический метод __getattr__
.
Скажем, у нас есть класс Foo
:
class Foo(object):
def bar(self):
return 'bar'
def baz(self):
return 'baz'
Допустим, мы взаимодействуем с некоторым кодом, который мы не контролируем, который требует, чтобы вывод Foo.bar()
был в верхнем регистре, и мы не хотим явно вызывать .upper()
в нашем коде.
Мы можем создать класс-оболочку, который перехватывает вызовы к Foo.bar()
, но прозрачно разрешает доступ к Foo
другим методам (это, по сути, шаблон адаптера ).
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
Этот класс Wrapper не будет сообщаться как Foo
с помощью type
или isinstance
проверок, но в противном случае он может использоваться вместо Foo
, если вызывающий код полагается на duck-typing вместо (не пифонической) явной проверки типов.
Перехват магических методов, таких как __str__
, должен выполняться явно.Это потому, что эти методы всегда ищутся непосредственно в классе экземпляра, поэтому __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