在Python 2.5中创建外观模式

1 投票
3 回答
1790 浏览
提问于 2025-04-15 14:33

我想创建一个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 个回答

0

我觉得Alex和Ben的回答都应该把他们的setattr调用修改成下面这样:

setattr(self.inner, n, value)
5

正如另一个回答所说,__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 中终于消失了]],这可不是你想要的……;-)。

6

这里你需要使用 __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)

撰写回答