Python 调用实例变量';从实例本身中删除

Python 调用实例变量';从实例本身中删除,python,methods,instance-variables,Python,Methods,Instance Variables,我希望能够从实例本身调用实例变量的常用方法。这对于程序的运行来说并不是必需的;但是,键入bar.baz()要比键入bar.foo.baz()方便得多 最具python风格/可读性/最常见的方法是什么?我想我应该写一个函数装饰器;然而,我对其他想法持开放态度。解决方案还必须是继承友好的 示例: class Foo (object) : def baz (self) : return 324 class Bar (object) : def __init__ (se

我希望能够从实例本身调用实例变量的常用方法。这对于程序的运行来说并不是必需的;但是,键入
bar.baz()
要比键入
bar.foo.baz()
方便得多

最具python风格/可读性/最常见的方法是什么?我想我应该写一个函数装饰器;然而,我对其他想法持开放态度。解决方案还必须是继承友好的

示例:

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() 
这是用于Python2.7.3的,仅供参考。

这更简单

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

您可以只做所谓的
mixin
。您创建的类实际上没有个人状态,但具有要“混合”到另一个类中的常见功能:

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

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

bar = Bar()
bar.baz()

*或者像@Joachim在另一个答案中建议的那样使用构图。

如果这只是一种方法,那么你得到的确实没有那么糟糕。它非常直截了当地说,
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
的所有方法都可以从包含
Foo
Bar
实例调用,则可以尝试使用
\uuu getattr\uuu

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
    的界面公开,这可能是不需要的
  • 当然,您可以在
    \uuu getattr\uuuu
    方法中添加更多的逻辑,以便只委派某些事情,而不是委派所有事情

    当所有的
    Bar
    都是
    Foo
    的简单包装器时,我倾向于使用这种方法,因为“a
    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()
    
    \uuuu getattr\uuuu
    方法相比,这种方法的优点在于,您有一个在读取代码时重定向的方法的显式列表,并且它们在运行时都“看起来”像
    条的正常属性,因为它们是正常属性。如果您只需要为一个或两个方法使用它,那么它显然比您的原始代码多得多!这有点微妙(需要通过默认参数将
    \u method
    传递到
    \u tmp\u func
    ,因为Python闭包的工作方式不一定很明显)。但是,在类装饰器中隐藏完成此操作的逻辑相对容易,这将使您能够创建更多的类,将它们的一些方法的实现委托给它们的一个属性


    在这类事情上,你可以想出很多不同的方法。

    但是如果
    baz
    只是一个实用方法,并且没有与
    Bar
    相关的状态,那么你就不需要类了。你只需要函数这实际上是我解决这个问题的第一个方法。但是,这个解决方案不能很好地处理继承,所以它是不存在的。@RectangleTangle:什么方面对继承不起作用?如果我让一个类从
    Bar
    继承,名为
    Buzz
    ,它有自己的方法名
    baz
    ,调用
    Bar
    \uuuuu init\uuuu
    方法时,
    Buzz.baz
    将被覆盖。@RectangleTangle:然后将Foo作为所有内容的基类。或者用我的混合器approach@RectangleTangle是的,我为你的例子选择了最简单的解决方案。当涉及到继承时,mixin(@jdi的解决方案)确实是一种“pythonic”的方式来实现它。