Clean way to disable `__setattr__` until after initialization

北慕城南 提交于 2021-02-04 13:07:35

问题


I've written the following wrapper class. I want to define __setattr__ such that it redirects all attributes to the wrapped class. However, this prevents me from initializing the wrapper class. Any elegant way to fix this?

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)

回答1:


You are catching all assignments, which prevents the constructor from assigning self.value. You can use self.__dict__ to access the instance dictionary. Try:

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

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

Another way using object.__setattr__:

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

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



回答2:


A way to disable the __setattr__ until after initialization without changing the self.value = value syntax in the __init__ method is covered here. In short, embed knowledge of initialization in the object and use it in the __setattr__ method. For your 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:


With __getattr__ overridden as well::

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:


As suggested in other answers, one idea is to directly access the object dictionary to bypass setattr resolution.

For something easy to read, I suggest the following:

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

Using vars is optional, but I find it nicer than directly accessing self.__dict__, and the inline dict() notation allows for grouping all instance variable initialization in a visible block with minimum boilerplate code overhead.



来源:https://stackoverflow.com/questions/12998926/clean-way-to-disable-setattr-until-after-initialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!