在Python 2.5中创建外观模式
我想创建一个Python类,它可以作为另一个Python类的包装器。
大概是这样的:
class xxx:
name = property( fset=lambda self, v: setattr(self.inner, 'name', v), fget=lambda self: getattr(self.inner, 'name' ))
def setWrapper( self, obj )
self.inner = obj
所以当有人说 xxx().x = 'hello' 时,我希望它能把值设置到 xxx().inner.whatever 而不是 xxx().x。
这样做可能吗?我试过用lambda,但没成功。我现在用的是Python 2.5。
编辑:现在我老婆不催我去睡觉,所以我可以把代码再完善一下。我对你们下面提到的内容有点想法,但从文档来看,似乎应该避免重写 __setattr__/__getattr__
,而是使用属性(property)。如果通过属性函数无法实现,那么我就会使用 __setattr__/__getattr__
?谢谢。
3 个回答
我觉得Alex和Ben的回答都应该把他们的setattr调用修改成下面这样:
setattr(self.inner, n, value)
正如另一个回答所说,__getattr__
和 __setattr__
是关键,但是 使用后者时需要小心……:
class Wrapper(object):
def __init__(self, wrapped):
object.__setattr__(self, 'inner', wrapped)
def __getattr__(self, n):
return getattr(self.inner, n)
def __setattr__(self, n, value):
setattr(self.inner, n, value)
对于 self.inner
的访问,你不需要特别小心,因为 __getattr__
只会在属性不存在时被调用;但是 __setattr__
会在每次设置属性时都被调用,所以当你真的需要设置 self.inner
(或者其他任何属性)时,你需要明确地绕过 __setattr__
(这里我使用 object
来实现这个目的,所以我也 继承 自 object
——在 Python 2.* 中这样做是非常推荐的,否则你会创建一个“旧式类”[[这种类在 Python 3 中终于消失了]],这可不是你想要的……;-)。
这里你需要使用 __setattr__
和 __getattr__
这两个方法,具体的用法可以在这里找到。
简单来说,如果你这样做:
class Wrapper(object):
def __init__(self, wrapped):
object.__setattr__(self, 'inner', wrapped)
def __getattr__(self, attr):
return getattr(self.inner, attr)
def __setattr__(self, attr, value):
setattr(self.inner, attr, value)
它应该能达到你想要的效果。我强烈建议你阅读上面链接的文档。
编辑:正如所指出的,原来的版本因为 __setattr__
被无条件调用而失败了。我已经更新了这个例子。请注意,这个版本依赖于新式类的行为(通过从对象继承来表示)。如果是旧式类,我想你需要像下面这样处理 __dict__
:
class OldStyleWrapper:
def __init__(self, wrapped):
self.__dict__['inner'] = wrapped
def __getattr__(self, attr):
return getattr(self.inner, attr)
def __setattr__(self, attr, value):
setattr(self.inner, attr, value)