【问题标题】:Clean way to disable `__setattr__` until after initialization在初始化之前禁用`__setattr__`的干净方法
【发布时间】:2012-10-11 12:35:30
【问题描述】:

我编写了以下包装类。我想定义 __setattr__ 以便它将所有属性重定向到包装类。但是,这会阻止我初始化包装类。有什么优雅的方法可以解决这个问题?

class Wrapper:
    def __init__(self, value):
        # How to use the default '__setattr__' inside '__init__'?
        self.value = value

    def __setattr__(self, name, value):
        setattr(self.value, name, value)

【问题讨论】:

  • Wrapper 包装了什么?为什么不继承object
  • @Tichodroma 它可以包装任何东西。我在 GUI 应用程序中使用它;当封闭的对象被修改时,包装器会通知侦听器。它不是从object 继承的,因为我只想使用 Python 3。

标签: python python-3.x setattr


【解决方案1】:

您正在捕获所有分配,这会阻止构造函数分配self.value。您可以使用self.__dict__ 访问实例字典。试试:

class Wrapper:
    def __init__(self, value):
        self.__dict__['value'] = value

    def __setattr__(self, name, value):
        setattr(self.value, name, value)

使用object.__setattr__的另一种方式:

class Wrapper(object):
    def __init__(self, value):
        object.__setattr__(self, 'value', value)

    def __setattr__(self, name, value):
        setattr(self.value, name, value)

【讨论】:

  • 不错。不过有一个问题:为什么我还要在__setattr__ 中使用self.__dict__['value']
  • @Paul 对不起,你不需要那个。我以为你也覆盖了__getattr__
【解决方案2】:

here 介绍了一种在初始化之前禁用 __setattr__ 而不更改 __init__ 方法中的 self.value = value 语法的方法。简而言之,在对象中嵌入初始化知识,并在__setattr__ 方法中使用它。给你的Wrapper

class Wrapper:
    __initialized = False
    def __init__(self, value):
        self.value = value
        self.__initialized = True

    def __setattr__(self, name, value):
        if self.__initialized:
            # your __setattr__ implementation here
        else:
            object.__setattr__(self, name, value)

【讨论】:

    【解决方案3】:

    __getattr__ 也被覆盖::

    class Wrapper:
        def __init__(self,wrapped):
            self.__dict__['wrapped'] = wrapped
        def __setattr__(self,name,value):
            setattr(self.__dict__['wrapped'],name,value)
        def __getattr__(self,name):
            return getattr(self.__dict__['wrapped'],name)
    
    
    class A:
        def __init__(self,a):
            self.a = a
    
    wa = Wrapper(A(3))
    #wa.a == wa.wrapped.a == 3
    

    【讨论】:

      【解决方案4】:

      正如其他答案中所建议的,一种想法是直接访问对象字典以绕过setattr 分辨率。

      为了便于阅读,我建议如下:

        def __init__(self,wrapped1, wrapped2):
             vars(self).update(dict(
                _wrapped1=wrapped1,
                _wrapped2=wrapped2,
              ))
      

      使用vars 是可选的,但我发现它比直接访问self.__dict__ 更好,并且内联dict() 表示法允许将所有实例变量初始化分组在一个可见块中,并且样板代码开销最小。

      【讨论】:

        猜你喜欢
        • 2013-07-12
        • 2013-01-13
        • 2013-02-26
        • 2023-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多