在Python中,我已经看到建议使用保持或包装来扩展对象或类的功能,而不是继承。特别是,我认为Alex Martelli在他的Python Design Patterns谈话中谈到了这件事。我已经看到这个模式用于依赖注入库,如pycontainer。我碰到的包装对象扩展/添加功能同时解决isinstance
的一个问题是,当我有一个使用 isinstance anti-pattern代码交互,因为保持/包装对象失败的isinstance
测试这种模式失败。如何设置持有/包装对象以避免不必要的类型检查?这可以做到一般吗?在某种意义上,我需要一些类似于保留签名的函数装饰器的类实例(例如,simple_decorator或Michele Simionato的decorator)。
资质:我并不是断言isinstance
的所有用法都不合适;几个答案对此有很好的说明。也就是说,应该认识到isinstance
的使用对对象交互造成了明显的限制 - 它强制继承成为多态的来源,而不是的行为。
对于这个问题究竟如何/为什么会出现一些混淆,所以让我举一个简单的例子(从pycontainer大致解除)。假设我们有一个Foo类,还有一个FooFactory。为了举例,假设我们希望能够实例化记录每个函数调用的Foo对象,或者不要考虑AOP。此外,我们希望在不修改Foo类/源的情况下执行此操作(例如,我们可能实际上正在实现一个通用工厂,可以在任何类实例上动态添加日志记录功能)。在这第一个刺可能是:
class Foo(object):
def bar():
print 'We\'re out of Red Leicester.'
class LogWrapped(object):
def __init__(self, wrapped):
self.wrapped = wrapped
def __getattr__(self, name):
attr = getattr(self.wrapped, name)
if not callable(attr):
return attr
else:
def fun(*args, **kwargs):
print 'Calling ', name
attr(*args, **kwargs)
print 'Called ', name
return fun
class FooFactory(object):
def get_foo(with_logging = False):
if not with_logging:
return Foo()
else:
return LogWrapped(Foo())
foo_fact = FooFactory()
my_foo = foo_fact.get_foo(True)
isinstance(my_foo, Foo) # False!
有5原因,你可能想要做的事情正是这样(用装饰代替,等等),但要记住:
- 我们不不想触摸Foo类。假设我们正在编写可供我们尚不知道的客户使用的框架代码。
- 重点是返回一个基本上是Foo的对象,但增加了一些功能。它应该看起来像是一个Foo ---尽可能---对任何期待Foo的客户代码。因此希望解决
isinstance
。 - 是的,我知道我不需要工厂班级(在这里抢先保护自己)。
摇动我的拳头无助愤怒在isinstance。你不能用isinstance修复代码吗? http://stackoverflow.com/questions/423823/whats-your-favorite-programmer-ignorance-pet-peeve/423857#423857 – 2009-02-23 22:52:18
无奈的愤怒:)在某些情况下,我有权访问isinstance。但另一个用例是希望编写与其他人很好的“框架”代码(例如pycontainer)。 – zweiterlinde 2009-02-23 23:02:54