从实例本身调用实例变量的方法

时间:2012-08-10 05:34:24

标签: python methods instance-variables

我有一种情况,我希望能够从实例本身调用实例变量的常用方法。这对于程序运行来说并不是必需的;但是,键入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,仅供参考。

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)

如果它只是一种方法,那么你所拥有的就是老实说也不是那么糟糕。它直截了当地说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的所有方法都可以从包含Bar的{​​{1}}实例调用,那么您可以尝试使用Foo }:

__getattr__

但这有一些明显的缺点。

  1. 目前尚不清楚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() 实际提供的方法,无论是通过阅读源代码还是通过内省。
  2. 所有Bar的方法和属性(不是由Foo直接提供的)都将通过Bar的界面公开,这可能是不受欢迎的。
  3. 当然,您可以在Bar方法中添加更多逻辑来仅委托某些内容,而不是所有内容。

    __getattr__所有BarFoo周围的简单包装时,我倾向于使用这种方法,因为“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的闭包工作方式并不一定明显。但是隐藏在类装饰器中执行此操作的逻辑包相对容易,这将使您能够创建更多类,将其某些方法的实现委托给其属性之一。

    你可以提出的这些事情有很多变化。