web-dev-qa-db-fra.com

Pourquoi utiliser __setattr__ en python?

Je ne sais pas pourquoi utiliser __setattr__ au lieu d'un simple référencement comme x.a=1.

Je comprends cet exemple:

class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0


x=Rectangle()
x.width=20
x.__setattr__('height',30)
setattr(x,'width',99)

mais ne comprenez pas pourquoi utiliser du code en fonction de la chaîne ('height').

Pourriez-vous m'expliquer quels sont les avantages de __setattr__?

21
user278618

Vous ne l'appelez pas vous-même. Période. Si vous devez utiliser une chaîne parce que vous ne connaissez pas le nom à l'avance ( very mauvaise idée dans 99% des cas où l'on pourrait penser qu'ils en ont besoin, presque toujours un dict ou une liste est préférable/choix plus sain), vous utilisez la fonction setattr intégrée.

Cependant, cela s’appelle pour vous - lorsque vous utilisez a.x = ..., c’est fait comme a.__setattr__('x', ...) (il s’agit probablement d’une simplification excessive). Et certains objets le surchargent pour permettre certaines ruses, par exemple. imiter l'immuabilité. Voir la documentation de "méthodes spéciales".

28
user395760

__setattr__ est une méthode de classe appelée par la méthode intégrée setattr. Autrement dit, si __setattr__ est défini dans une classe donnée. La plupart du temps, vous ne déclarez pas votre propre version de __setattr__. Je suppose donc que vous demandez quelle est l'utilisation de la méthode setattr.

Supposons que vous avez une variable portant le nom de l'attribut que vous souhaitez définir au lieu de simplement connaître le nom:

class A(object):
    def doSth(self, name, val):
        setattr(self, name, val)

impossible à faire avec self.name = val

En outre, les arguments de mot clé sont couramment utilisés:

class A(object):
    def __init__(self, *args, **kwargs):
        for k,v in kwargs.items():
            setattr(self, k, v)
15
pajton

Je peux imaginer une application dans laquelle, par exemple, vous substituez __setattr__ et __getattr__ pour fournir un accès semblable à un objet à une autre structure de données qui n'est pas conservée en mémoire. Par exemple, vous pouvez créer un objet où foo.CustomerName = "John" a mis à jour la colonne CustomerName dans une ligne de la base de données pointée par foo afin de contenir la valeur "John". C'est-à-dire, foo.__setattr__ utiliserait le nom et la valeur de l'attribut pour construire une commande permettant de mettre à jour une base de données sur le disque. Je détesterais devoir écrire une telle chose, mais ce serait possible.

7
Peter Milley

Notez que __xxx__ sont des méthodes de surcharge d'opérateur de la classe et ne doivent donc être utilisés que dans des situations spéciales et non dans des cas comme dans votre exemple.

Par exemple, __setattr__ intercepte toutes les attributions d'attributs et peut être utilisé pour modifier le comportement de votre classe lorsqu'une valeur est affectée à un attribut.

2
joaquin

le __setattr__ peut être utilisé pour la réflexion, où une propriété sur l'objet Rectangle peut être créée à l'exécution, il y en a plus à ce sujet sur http://en.wikipedia.org/wiki/Reflection_%28computer_science%29

class Rectangle:
    def __init__(self):
        #... code ...

x = Rectangle()
#x.__setattr__('newProperty',30)      Edited after comment
setattr(x, 'newProperty', 30)
print x.newProperty #>>> 30
1
aweis

La première utilisation de __setattr__ consiste à être écrasé dans une définition de classe.

class Foo ( object ) :

    def __init__ ( self ) :
        self.x = 'looser'

    def __setattr__ ( self, name, value ) :
        if name == 'x' :
            print( 'Hello, {} !'.format( value ) )
            self.x = value

Problème, Foo() imprimera une séquence infinie de:

'Hello, looser !'

La deuxième utilisation est que, lorsque vous le faites, vous pouvez appeler setattr depuis la classe parente (object par défaut) pour éviter la récursion infite:

class Foo ( object ) :

    def __setattr__ ( self, name, value ) :
        self.bar( name, value )
        object.__setattr__( self, name, value )

    def bar ( self, name, value ) :
        print( 'Setting {} to {}.'.format( name, value ) )

Et donc :

f = Foo()

>> 'Hello, winner !'

f.x

>> 'winner'
0
Thrastylon
class Name(object):
    pass

obj=Name()

#just i have created object two way 
#first

obj.a="first"
print obj.a

#answer= "first"
#second

obj.__setattr__('b','second')
print obj.a
#answer= "second"
0
user3657729