webentwicklung-frage-antwort-db.com.de

Python-Klassenmitglieder

Ich lerne gerade Python und komme aus einem C-Hintergrund, also lassen Sie es mich wissen, wenn ich Verwirrung/Verwechslung zwischen beiden habe.

Angenommen, ich habe folgende Klasse:

class Node(object):
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

    @classmethod
    def tree(cls, element, left, right):
        node = cls(element)
        node.left = left
        node.right = right
        return node

Dies ist eine Klasse mit dem Namen Node, die den Konstruktor überlastet, um bei Bedarf andere Argumente verarbeiten zu können.

Was ist der Unterschied zwischen der Definition von self.element in __init__ (wie oben gezeigt) und nicht wie folgt:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

Ist self.element in __init__ nicht identisch mit der definierten Variablen element der Klasse? Würde das nicht einfach element von None auf den element-Wert überschreiben, der in __init__ übergeben wurde?

40
darksky

Eines ist ein Klassenattribut, während das andere ein Instanzattribut ist. Sie sind unterschiedlich, aber sie sind eng miteinander verbunden, so dass sie manchmal gleich aussehen. 

Es hat damit zu tun, wie Python Attribute nachschlägt. Es gibt eine Hierarchie. In einfachen Fällen könnte es so aussehen:

instance -> Subclass -> Superclass -> object (built-in type)

Wenn Sie in instance nach einem Attribut wie diesem suchen ...

`instance.val`

... was tatsächlich passiert ist, dass zuerst , Python in der Instanz selbst nach val sucht. Wenn val dann nicht gefunden wird, sieht es in seiner Klasse Subclass aus. Wenn dort val nicht gefunden wird, wird im übergeordneten Element von Subclass, Superclass gesucht. Dies bedeutet, dass wenn Sie dies tun ...

>>> class Foo():
    foovar = 10  
    def __init__(self, val):
        self.selfvar = val

... alle Instanzen von Foo share foovar, aber ihre eigenen selfvars. Hier ist ein einfaches, konkretes Beispiel, wie das funktioniert:

>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10

Wenn wir foovar nicht berühren, ist es für f und Foo gleich. Aber wenn wir f.foovar... ändern.

>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10

... fügen wir ein Instanzattribut hinzu, das den Wert von Foo.foovar effektiv maskiert. Wenn wir Foo.foovar direkt ändern, hat dies keine Auswirkungen auf unsere foo-Instanz:

>>> Foo.foovar = 7
>>> f.foovar
5

Es wirkt sich jedoch auf eine neue foo-Instanz aus:

>>> Foo(5).foovar
7

Denken Sie auch daran, dass veränderliche Objekte eine weitere Ebene der Indirektion hinzufügen (wie mgilson mich daran erinnert). Hier bezieht sich f.foovar auf dasselbe Objekt wie Foo.foovar. Wenn Sie also das Objekt ändern, werden die Änderungen in der Hierarchie weitergegeben:

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]
65
senderle

In Python können Klassenvariablen und Instanzvariablen mit demselben Namen verwendet werden. Sie befinden sich separat im Speicher und werden ganz unterschiedlich abgerufen.

In Ihrem Code:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

Die ersten Variablen (außerhalb der __init__-Funktion) werden Klassenvariablen genannt. Auf diese kann anschließend mit Node.element usw. zugegriffen werden. Diese entsprechen statischen Member-Variablen in C++ und werden von allen Instanzen der Klasse gemeinsam verwendet.

Der zweite Variablensatz (innerhalb der __init__-Funktion) wird als Instanzvariable bezeichnet. Auf diese wird über das self-Objekt zugegriffen, z. self.element oder durch den Instanznamen, z. myNode.element außerhalb der Klasse.

Es ist wichtig zu beachten, dass Sie entweder das Formular self.variable oder Node.variable verwenden müssen, um auf eines dieser Elemente in einer Member-Funktion zuzugreifen. Durch den Zugriff auf variable wird versucht, auf eine lokale Variable namens variable zuzugreifen.

11
Lee Netherton

self.element innerhalb des Konstruktors ist eine Instanzvariable (wenn ein Knotenobjekt seinen Wert ändert, ändert es sich nur für dieses Objekt), wobei das in der zweiten Version eine Klassenvariable ist (wenn also ein Knotenobjekt seinen Wert ändert, wird es für alle geändert.) Knotenobjekte).

Die Analogie in C++ wäre nicht statisch gegenüber statischen Elementvariablen in Ihrer Klasse.

2
Borgleader

Der wichtige Teil ist das Argument self für __init__. In der any instance-Methode wird dies das erste Argument sein. Dies geschieht durch das Design. In Python können Sie tatsächlich nur während des Methodenaufrufs auf die Instanz zugreifen. Dies wird explizit mit dem Argument self angezeigt.

Wenn Sie sich in einer class-Definition befinden, haben Sie noch keine Instanzen. Sie ändern also wirklich die Klasse selbst. Wenn Sie also Attribute auf Klassenebene definieren, werden sie zu Klassenattributen und nicht zu Instanzen.

Wenn man es mit einem C (++) vergleicht, könnte man wahrscheinlich sagen, dass "Klassen" in diesen Sprachen im Wesentlichen Blaupausen für die Objekte sind, die sie repräsentieren. "Diese Objekte müssen die Attribute foo und bar und zusätzlich die folgenden Methoden haben." In Python sind Klassen jedoch selbst Objekte, und ihre Hauptstärke besteht darin, dass sie Kopien (Instanzen) von sich selbst erstellen können, die auch die Methoden der Klasse verwenden. Es ist also eher so, als hätten Sie foo und bar als Klassenattribute und zusätzlich die folgende Methode, mit der Sie Instanzen erstellen können.

Anstelle eines Bauplans ist dies eher eine Schritt-für-Schritt-Anleitung.

0
voithos

self.element in der init ist eine Instanzvariable. Sie können sie in einer anderen Memberfunktion abrufen/setzen, indem Sie self.element eingeben. Das in der Klasse deklarierte Element ist die Klassenvariable. Sie können es durch Eingabe von Node.element abrufen/festlegen.

0
waitingkuo

wenn Sie versuchen, auf die Variable mit einer Klasse zuzugreifen, sehen Sie nur in 

cls.__dict__

wenn Sie jedoch versuchen, auf die Variable mit der Instanz zuzugreifen, wird sie zuerst angezeigt 

self.__dict__ 

wenn find dann zurückkommt oder wenn nicht finden kann, dann schaut es auch rein 

cls.__dict__

hier ist Cls die Klasse 

class Test:
    temp_1=10
    temp_2=20

    def __init__(self):
        self.test_1=10
        self.test_2=20

    @classmethod
    def c_test(cls):
        pass

    def t_method(self):
        pass


print Test.__dict__
print Test().__dict__

Ausgabe:

{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20}

{'test_2': 20, 'test_1': 10}

Für Details Klasse Spezialattribut

0
Kallz