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
的简单包装器时,我倾向于使用这种方法,因为“aBar
的行为大部分类似于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”的方式来实现它。