18 votes

Une façon propre de désactiver `__setattr__` jusqu'après l'initialisation

J'ai écrit la classe wrapper suivante. Je veux définir __setattr__ de telle sorte qu'il redirige tous les attributs vers la classe enveloppée. Cependant, cela m'empêche d'initialiser la classe enveloppante. Y a-t-il un moyen élégant de résoudre ce problème ?

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)

18voto

xiaomao Points 1576

Vous attrapez toutes les assignations, ce qui empêche le constructeur d'assigner self.value . Vous pouvez utiliser self.__dict__ pour accéder au dictionnaire d'instance. Essayez :

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

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

Une autre façon d'utiliser object.__setattr__ :

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

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

11voto

fragapanagos Points 599

Un moyen de désactiver le __setattr__ jusqu'après l'initialisation sans modifier le self.value = value dans la syntaxe __init__ La méthode est couverte aquí . En bref, il faut intégrer la connaissance de l'initialisation dans l'objet et l'utiliser dans le processus d'initialisation. __setattr__ méthode. Pour votre 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)

0voto

Roland Puntaier Points 519

Avec __getattr__ sont également remplacés : :

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

0voto

Sylvain Leroux Points 9401

Comme suggéré dans d'autres réponses, une idée est d'accéder directement au dictionnaire d'objet pour contourner setattr résolution.

Pour quelque chose de facile à lire, je suggère ce qui suit :

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

Utilisation de vars est facultatif, mais je trouve cela plus agréable que d'accéder directement à self.__dict__ et la version en ligne dict() permet de regrouper toutes les initialisations de variables d'instance dans un bloc visible avec un minimum de code passe-partout.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X