我有一种情况,我希望能够从实例本身调用实例变量的常用方法。这对于程序运行来说并不是必需的;但是,键入bar.baz()
而不是bar.foo.baz()
更方便。
最接近Pythonic /可读/最常见的方法是什么?我在想我会写一个函数装饰器;但是,我对其他想法持开放态度。解决方案还必须是继承友好的。
示例:
class Foo (object) :
def baz (self) :
return 324
class Bar (object) :
def __init__ (self) :
self.foo = Foo()
# This is the current ugly solution.
# It also results in an extra function call.
def baz (self, *args, **kw) :
return self.foo.baz(*args, **kw)
bar = Bar()
print bar.foo.baz()
print bar.baz()
这适用于Python 2.7.3,仅供参考。
答案 0 :(得分:4)
您可以执行所谓的mixin
。你创建了一个真正没有个人状态的类,但是它具有你想要“混入”另一个类的常用功能:
class FooMixin(object) :
def baz (self) :
return 324
class Bar(object, FooMixin):
def __init__ (self):
pass
bar = Bar()
bar.baz()
*或者使用像@Joachim这样的构图在另一个答案中建议。
答案 1 :(得分:2)
这更简单;
class Foo (object) :
def baz (self) :
return 324
class Bar (object) :
def __init__ (self) :
self.foo = Foo()
self.baz = self.foo.baz;
bar = Bar()
print bar.foo.baz()
print bar.baz()
答案 2 :(得分:1)
如果它只是一种方法,那么你所拥有的就是老实说也不是那么糟糕。它直截了当地说baz
是Boo
接口的一部分,它通过委托给包含的Foo
实例来实现这一点。
略短的版本是使用属性:
class Foo (object) :
def baz (self) :
return 324
class Bar (object) :
def __init__ (self) :
self.foo = Foo()
@property
def baz(self):
return self.foo.baz
def __getattr__(self, attr):
return getattr(self.foo, attr)
bar = Bar()
print bar.foo.baz()
print bar.baz()
虽然还有一个额外的函数调用,但baz
是一种方法可能稍微不那么明显。
如果baz
是唯一需要委托给包含的实例的方法,那么如果不依赖于重写继承树,我就会使用你所拥有的。如果您想委派许多方法,那么有一些选择:
如果您希望Foo
的所有方法都可以从包含Bar
的{{1}}实例调用,那么您可以尝试使用Foo
}:
__getattr__
但这有一些明显的缺点。
class Foo (object) :
def baz (self) :
return 324
class Bar (object) :
def __init__ (self) :
self.foo = Foo()
def __getattr__(self, attr):
return getattr(self.foo, attr)
bar = Bar()
print bar.foo.baz()
print bar.baz()
实际提供的方法,无论是通过阅读源代码还是通过内省。Bar
的方法和属性(不是由Foo
直接提供的)都将通过Bar
的界面公开,这可能是不受欢迎的。当然,您可以在Bar
方法中添加更多逻辑来仅委托某些内容,而不是所有内容。
当__getattr__
所有Bar
是Foo
周围的简单包装时,我倾向于使用这种方法,因为“Bar
的行为大致类似于Foo
“是概念界面的一部分(而不是Foo
是一个内部实现细节),它将Bar
的定义简化为描述不的方式Foo
。
另一种方法是使用Python的动态特性来定义委托给Bar
的{{1}}的属性,而不必全部手写它们。像这样的东西可以解决这个问题:
Foo
这种方法优于class Foo (object) :
def baz (self) :
return 324
class Bar (object) :
def __init__ (self) :
self.foo = Foo()
for _method in ['baz', 'blob']:
@property
def _tmp_func(self, _name=_method):
return getattr(self.foo, _name)
locals()[_method] = _tmp_func
# del to avoid name pollution
del _method, _tmp_func
bar = Bar()
print bar.foo.baz()
print bar.baz()
的优点是你有一个显式的方法列表,当你阅读代码时,这些方法被重定向,并且它们都会“看起来像”正常属性__getattr__
在运行时,因为它们是正常属性。如果您只需要一个或两个方法,那么显然代码比原始代码多得多!它有点微妙(需要通过默认参数将Bar
传递给_method
,因为Python的闭包工作方式并不一定明显。但是隐藏在类装饰器中执行此操作的逻辑包相对容易,这将使您能够创建更多类,将其某些方法的实现委托给其属性之一。
你可以提出的这些事情有很多变化。