まえがき
継承より委譲という言葉も当たり前の言葉になっているような昨今、委譲のためにあるオブジェクトをwrapしたクラスを作るということはよくありますね。
そのような場合にisinstanceで分岐している部分が厄介になったりするのですが。(これに関してはそもそもducktypingを行わない分岐を使うコードが良く
ないという話もあります)
isinstanceの分岐をごまかすことは出来るでしょうか?
__class__というpropertyを定義する。
isinstanceの分岐をごまかすにはどうすれば良いかということですが。意外と簡単で __class__ というproperty
を定義してあげればisinstanceで評価する際にそちらを見に行きます。
確認のためのコード
以下で挙動を試してみることにします。UserオブジェクトをLoggedWrapperというWrapperオブジェクトでwrapした場合について。
isinstanceの分岐をごまかせているか確認しています。
# -*- coding:utf-8 -*-
import logging
logger = logging.getLogger(__name__)
class LoggedWrapper(object):
def __init__(self, ob):
self.ob = ob
def __getattr__(self, k):
logger.debug("action:%s", k)
return getattr(self.ob, k)
@property
def __class__(self):
return self.ob.__class__
from collections import namedtuple
User = namedtuple("User", "name age")
user = User("foo", 20)
wrapped = LoggedWrapper(user)
logging.basicConfig(level=logging.NOTSET)
print(wrapped.name)
print(wrapped.age)
# DEBUG:__main__:action:name
# foo
# DEBUG:__main__:action:age
# 20
print(isinstance(wrapped, User))
# True
ちなみに __class__ はWrapperオブジェクトに存在しているためlogは出力されません。