2012-08-10 127 views
3

我有一种情况,我希望能够从实例本身调用实例变量的常用方法。这对程序来说并不是真正必要的功能;然而,键入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,FYI。

+1

但是,如果'baz'只是一种实用方法,并且没有与Bar有关的状态,那么你就不需要一个类。你只需要功能 – jdi 2012-08-10 05:38:05

回答

1

如果只是一种方法,那么你得到的东西并不是那么糟糕。它很直截了当地说bazBoo的接口的一部分,它通过委托给包含的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所有方法是从含有FooBar情况下可调用的,那么你可以尝试使用__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() 

但是这有一些明显的缺点。

  1. 目前还不清楚什么方法Bar实际上提供,或者通过阅读源代码或内省。
  2. 所有Foo的方法和属性(不直接由Bar提供)将通过Bar的接口公开,这可能是不希望的。

当然,您可以在__getattr__方法中放置更多的逻辑来仅委托某些事物,而不是所有事物。

我倾向于去用这种方法时全部Bar是一个Foo围绕一个简单的包装,因为那时“一Bar行为大多喜欢一个Foo”是概念上的接口(而不是Foo是内部的一部分实现细节),并且它减少了Bar的定义,以描述它的方式为而不是,如Foo

另一种方法是使用Python的动态特性来定义Bar上的属性,该属性委托给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的普通属性,因为它们是正常的属性。如果你只需要一个或两个方法,它显然比你的原始代码多得多!这有点微妙(因为Python关闭的工作方式不一定很明显,需要通过默认参数将_method转换为_tmp_func)。但是隐藏在类装饰器中隐藏这样做的逻辑是相对容易的,这会让你能够创建更多的类,将其某些方法的实现委派给它们的一个属性。

在这些你可以想到的事情上有许多变化。

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() 
+0

这实际上是我第一个解决问题的方法。然而,这种解决方案在继承方面效果不佳,所以它不在表格中。 – rectangletangle 2012-08-10 05:42:57

+0

@RectangleTangle:什么方面不适合继承? – jdi 2012-08-10 05:43:34

+0

如果我要从'Bar'继承一个名为'Buzz'的类,它有自己的方法名'baz','Bar'的'__init__'方法被调用时'Buzz.baz'会被覆盖。 – rectangletangle 2012-08-10 05:46:08

4

你可以做所谓的mixin。您创建一个真正有没有个人状态的类,但携带你想“混”到另一个类常用功能:

class FooMixin(object) : 
    def baz (self) : 
     return 324 

class Bar(object, FooMixin): 
    def __init__ (self): 
     pass 

bar = Bar() 
bar.baz() 

*也可以使用像@Joachim成分表明在对方的回答。

+0

大概虽然“Foo”的“真实”版本会有*方法*取决于某些内部状态。 – Ben 2012-08-10 06:50:17