2016-11-30 2 views
3

Ich habe eine Klasse mit vielen Instanzvariablen mit Standardwerten, die in instantiantion optional außer Kraft gesetzt werden kann (Anmerkung: keine änderbare Standardargumente).Python: programmatische Klasse Instanz-Variable Initialisierung mit Einheimischen()

Da es ziemlich überflüssig ist self.x = x usw. oft zu schreiben, initialisiere ich die Variablen programmatisch.

Zur Veranschaulichung betrachten Sie dieses Beispiel (die aus Gründen der Kürze nur 5 Instanzvariablen und alle Methoden weggelassen hat):

Beispiel: So

# The "painful" way 
class A: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.a = a 
     self.b = b 
     self.c = c 
     self.d = d 
     self.e = e 

# The "lazy" way 
class B: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.__dict__.update({k: v for k, v in locals().items() if k!='self'}) 

# The "better lazy" way suggested 
class C: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
      for k, v in locals().items(): 
       if k != 'self': 
        setattr(self, k, v) 

x = A(1, c=7) 
y = B(1, c=7) 
z = C(1, c=7) 

print(x.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(y.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(z.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 

zu machen mein Leben einfacher, verwende ich das Idiom in der Klasse B gezeigt, die das gleiche Ergebnis wie A.

Ist die schlechte Praxis ergibt? Gibt es irgendwelche Fallstricke?

Nachtrag: Ein weiterer Grund, dieses Idiom zu verwenden war, um Platz zu sparen - ich habe es in MicroPython verwenden soll. Aus welchen Gründen auch immerBecause locals work differently there arbeitet nur der Weg, der in Klasse A gezeigt wird.

+1

Ja. Es ist eine schlechte Übung. Warum nicht ein 'dict()' verwenden? Müssen sie Klassenattribute sein? –

+4

Related: http://stackoverflow.com/q/1389180/3001761. – jonrsharpe

+2

Ich kann mir keine offensichtlichen Fallstricke vorstellen, aber ich finde es ziemlich eklig. – wim

Antwort

3

Ich würde vorschlagen, den Code tatsächlich in class A gezeigt werden. Was Sie haben, ist repetitiven Code, nicht redundanten Code und repetitiv ist nicht immer schlecht. Sie müssen nur __init__ einmal schreiben, und eine Zuweisung pro Instanzvariable ist eine gute Dokumentation (explizit und klar) für welche Instanzvariablen Ihre Klasse erwartet.

Eine Sache zu beachten, ist jedoch, dass auch viele Variablen, die Sie als unterschiedliche Parameter initialisieren können ein Zeichen sein, dass Ihre Klasse neu entworfen werden muss. Wären einige der einzelnen Parameter sinnvoller in separate Listen, Dicts oder sogar zusätzliche Klassen gruppiert?

+1

Alex Martelli sagte etwas [sollte in der stdlib] (http://stackoverflow.com/questions/1389180/python-automatisch-initialize-instance-variables#comment1230512_1389224) zu sein vermeide diese Wiederholung. Und doch, 7 Jahre später, gibt es nichts. Also ..... ¯ \\ _ (ツ) _/¯ .... hier, habe +1. – wim

1

einen pythonic Ansatz versuchen:

class C: 
    def __init__(self,a,b=2,c=3,d=4.5,e=5): 
    for k,v in locals().iteritems(): 
     setattr(self,k,v) 
c = C(1) 
print c.a, c.b 
1 2 

Dieser Ansatz eine Linie oder zwei sein kann, länger, aber die Leitungslängen sind kürzer, und Ihre Absicht weniger gewunden. Darüber hinaus kann jeder, der versucht, Ihren Code wiederzuverwenden, auf die Attribute Ihrer Objekte wie erwartet zugreifen.

Hoffe, das hilft.

Edit: entfernt zweiten Ansatz kwargs bc es nicht Standardvariable Anforderung nicht adressieren.

Hier ist wichtig, dass ein Benutzer Ihres Codes nicht wie erwartet auf die Attribute Ihres Objekts zugreifen kann, wenn dies wie in der Beispielklasse B ausgeführt wird.

+0

'kwargs' ist in diesem Fall nicht nützlich: Es ist nicht garantiert, dass alle benötigten Variablen übergeben werden und nicht benötigte Variablen können als Instanzvariablen übergeben und gespeichert werden. – phoibos

+3

Ihr zweiter Ansatz erlaubt keine Standardeinstellungen, die in der Frage eindeutig erwünscht sind. In Ihrem ersten Ansatz, "self" von Ihrer Iteration auszuschließen – donkopotamus

+0

Guter Punkt, verwenden Sie den ersten Ansatz, wenn Standardwerte erforderlich sind. @donkopotamus: setattr erwartet 3 Argumente. Der erste muss eine Instanz des Objekts sein. Wenn innerhalb der Klassendefinition gearbeitet wird, muss diese Instanz self sein. –

Verwandte Themen