2013-07-09 12 views
5

Ich bin sehr neu in der Programmierung und fing an, Python zu lernen. Könnte eine sehr dumme Frage sein, bitte verzeihen Sie meine Unwissenheit. Betrachten Sie das folgende Code-Snippet:Python-Klasse-Attribute verstehen

class Test1: 
    bar = 10  
    def display(self,foo): 
     self.foo=foo 
     print "foo : ",self.foo #80 
    def display1(self): 
     print "bar: ", self.bar #10 
     print "again foo: ", self.foo #80 

if __name__ == '__main__': 
    test1 = Test1() 
    test1.display(80) 
    test1.display1() 
    print test1.bar #10 
    print test1.foo #80 

ich verstehen will, was der Unterschied ist foo und bar zwischen der Verwendung von (WRT, wo wir sie haben definiert) nach Umfang weise sie an allen Orten gleichermaßen zugänglich sind im Vergleich zu jeder andere und einzige Unterschied ist, dass man innerhalb der Funktion ist und andere innerhalb der Klasse, aber beide sind immer noch "Instanz" Variable. Also was ist eine gute Übung?

Auch, wenn ich etwas wie unten Anzeigefunktion ändern:

def display(self,foo): 
     self.foo=foo 
     foo = foo 
     print "self.foo : ",self.foo 
     print "foo : ",foo 

Kann jemand bitte erklären, wie Python dies sieht, wie in welchem ​​Unterschied/Bedeutung dieses self Schlüsselwort bringt zwischen zwei foo.

+4

Nein, 'bar' ist * nicht * eine Instanzvariable. Die beiden sind sehr unterschiedlich, weshalb es nicht um "gute Praxis" geht. Es geht darum, was für Ihre Situation angemessen ist, weil sie verschiedenen Zwecken dienen. – phant0m

+1

Auch 'self.bar' funktioniert, weil der Name' bar' zuerst im Namespace der Instanz und dann in der Klasse gesucht wird. Die Tatsache, dass "self.bar" funktioniert, bedeutet nicht immer, dass "bar" eine Instanzvariable ist. – ersran9

Antwort

3

bar ist ein Klassenattribut. da Klassen in Python sind Objekte, auch sie können Attribute habenist zufällig auf diesem Test Objekt zu leben, nicht ein Beispiel davon.

Aufgrund der Art und Weise, wie Python Attribut-Lookups auflöst, sieht es so aus, als ob test1 ein bar Attribut hat, aber das tut es nicht.

foo auf der anderen Seite lebt auf der Instanz test1 nach dem Aufruf display(80). Dies bedeutet, dass verschiedene Instanzen von Test unterschiedliche Werte in ihren jeweiligen foo Attributen haben können.

Natürlich könnten Sie Klassenvariablen als eine Art "gemeinsamen Standardwert" verwenden, die Sie dann mit einem Instanzattribut "überschreiben" können, aber das könnte verwirrend werden.

Zweite Frage

def display(self,foo): 
    self.foo=foo 
    foo = foo 
    print "self.foo : ",self.foo 
    print "foo : ",foo 

Lassen Sie sich nur ein Detail aus dem Weg: self ist kein Schlüsselwort, es ist nur Konvention ist das erste Argument „Selbst“ zu nennen, könnte man es auch „das nennt "oder" das "oder" Bar ", wenn Sie möchten, aber ich würde das nicht empfehlen.

Python übergibt das Objekt, auf dem die Methode als erstes Argument aufgerufen wurde.

def display(self,foo): 

Dieser foo ist der Name des ersten Parameters der Display-Instanz-Funktion.

self.foo=foo 

Dies setzt das Attribut mit dem Namen „foo“ der Instanz, auf das Sie display() auf den Wert genannt, die Sie als erstes Argument übergeben. Mit Ihrem Beispiel test1.display(80), self wird test1, foo ist 80 und test1.foo wird somit auf 80 gesetzt werden.

foo = foo 

Das macht gar nichts. Es verweist auf den ersten Parameter foo. Die nächsten beiden Zeilen verweisen wieder auf die Instanzvariable foo und den ersten Parameter foo.

4

bar ist ein Klassenattribut und foo ist ein Instanzattribut. Der wesentliche Unterschied besteht darin, dass bar für alle Klasseninstanzen zur Verfügung stehen wird, während foo nur auf eine Instanz verfügbar sein wird, wenn Sie die Anzeige auf dieser Instanz

>>> ins1 = Test1() 

ins1.bar funktioniert gut nennen, weil es ein Klassenattribut ist und von allen geteilt Instanzen.

>>> ins1.bar 
10 

Aber man kann nicht foo direkt hier zugreifen, da es noch nicht definiert ist:

>>> ins1.foo 
Traceback (most recent call last): 
    File "<ipython-input-62-9495b4da308f>", line 1, in <module> 
    ins1.foo 
AttributeError: Test1 instance has no attribute 'foo' 

>>> ins1.display(12) 
foo : 12 
>>> ins1.foo 
12 

Wenn Sie einig Instanz initialisieren mögen Attribute, wenn die Instanz sie dann innerhalb der __init__ Methode erstellt wird, legen .

class A(object): 
    bar = 10 
    def __init__(self, foo): 
     self.foo = foo #this gets initialized when the instance is created 
    def func(self, x): 
     self.spam = x #this will be available only when you call func() on the instance 
...   
>>> a = A(10) 
>>> a.bar 
10 
>>> a.foo 
10 
>>> a.spam 
Traceback (most recent call last): 
    File "<ipython-input-85-3b4ed07da1b4>", line 1, in <module> 
    a.spam 
AttributeError: 'A' object has no attribute 'spam' 

>>> a.func(2) 
>>> a.spam 
2 
+1

Ich denke, der Hauptunterschied besteht darin, dass ein Klassenattribut "freigegeben" ist, nicht dass es für alle Instanzen verfügbar ist. – phant0m

1

Ich persönlich mag es nicht, über Instanzvariablen innerhalb von anderen Verfahren als __init__ oder als Klassenvariablen wie bar in Ihrem Beispiel zu definieren.

Noch einmal persönlich, ich sehe gerne jedes Mitglied meiner Klasse, indem ich oben schaue. Ob es eine Klassenvariable ist, die Sie als Instanzvariable verwenden (etwas, was ich normalerweise nicht tue), oder eine Instanzvariable, die in __init__ definiert ist, es ist leicht zu erkennen, was in einer Klasse definiert ist und was nicht der Klassendefinition.

Wenn Sie nicht eine Variable als Klassenmitglied zugreifen müssen (dh. Sie es dort nur definieren zu vermeiden self.variable = val im __init__ Methode zu schreiben, dann würde ich klar die Finger davon lassen. Wenn Sie für den Zugriff benötigen es als Klassenvariable, tut dann, was Sie sind mit bar in meinem Buch ist ok.

Dies würde schreiben Sie Klasse meine bevorzugte Art und Weise sein.

class Test1: 

    def __init__(self): 
     self.foo = None 
     self.bar = 10 

    def display(self,foo): 
     self.foo=foo 
     print "foo : ",self.foo #80 

    def display1(self): 
     print "bar: ", self.bar #10 
     print "again foo: ", self.foo #80