Okay, das Wichtigste zuerst.
In Python gibt es keine "Variablendeklaration" oder "Variableninitialisierung".
Es gibt einfach das, was wir "Zuweisung" nennen, aber wahrscheinlich nur "Benennung".
Zuweisung bedeutet "dieser Name auf der linken Seite bezieht sich jetzt auf das Ergebnis der Bewertung der rechten Seite, unabhängig davon, worauf zuvor Bezug genommen wurde (wenn überhaupt)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
Daher haben Pythons Namen (wahrscheinlich ein besserer Begriff als "Variablen") keine zugeordneten Typen. die Werte tun. Sie können denselben Namen unabhängig von seinem Typ erneut auf alles anwenden, aber das Ding hat immer noch ein Verhalten, das von seinem Typ abhängt. Der Name ist einfach eine Möglichkeit, sich auf den Wert (das Objekt) zu beziehen. Dies beantwortet Ihre zweite Frage: Sie erstellen keine Variablen für einen benutzerdefinierten Typ. Sie erstellen keine Variablen für einen bestimmten Typ. Sie "erstellen" überhaupt keine Variablen. Sie geben Objekten Namen.
Zweiter Punkt: Python folgt einer sehr einfachen Regel, wenn es um Klassen geht, die tatsächlich viel konsistenter ist als die Sprachen wie Java, C ++ und C #: Alles, was im classBlock deklariert ist , ist Teil der Klasse . defHier geschriebene Funktionen ( ) sind also Methoden, dh ein Teil des Klassenobjekts (nicht auf Instanzbasis gespeichert), genau wie in Java, C ++ und C #; aber auch andere Namen hier sind auch Teil der Klasse. Auch hier sind die Namen nur Namen, und sie haben keine zugeordneten Typen, und Funktionen sind auch Objekte in Python. So:
class Example:
data = 42
def method(self): pass
Klassen sind in Python auch Objekte .
Jetzt haben wir ein Objekt mit dem Namen erstellt Example, das die Klasse aller Dinge darstellt, die Examples sind. Dieses Objekt verfügt über zwei vom Benutzer bereitgestellte Attribute (in C ++ "Mitglieder"; in C # "Felder oder Eigenschaften oder Methoden"; in Java "Felder oder Methoden"). Einer von ihnen heißt dataund speichert den ganzzahligen Wert 42. Der andere heißt methodund speichert ein Funktionsobjekt. (Es gibt mehrere weitere Attribute, die Python automatisch hinzufügt.)
Diese Attribute sind jedoch immer noch nicht wirklich Teil des Objekts. Grundsätzlich ist ein Objekt nur ein Bündel weiterer Namen (die Attributnamen), bis Sie zu Dingen kommen, die nicht mehr aufgeteilt werden können. Auf diese Weise können Werte zwischen verschiedenen Instanzen einer Klasse oder sogar zwischen Objekten verschiedener Klassen geteilt werden, wenn Sie dies absichtlich einrichten.
Erstellen wir eine Instanz:
x = Example()
Jetzt haben wir ein separates Objekt namens x, das eine Instanz von ist Example. Die dataund methodsind eigentlich nicht Teil des Objekts, aber wir können sie trotzdem nachschlagen, xweil Python hinter den Kulissen etwas magisches tut. methodInsbesondere wenn wir nachschlagen , erhalten wir stattdessen eine "gebundene Methode" (wenn wir sie aufrufen, xwird sie automatisch als selfParameter übergeben, was nicht passieren kann, wenn wir Example.methoddirekt nachschlagen ).
Was passiert, wenn wir versuchen zu verwenden x.data?
Wenn wir es untersuchen, wird es zuerst im Objekt nachgeschlagen. Wenn es nicht im Objekt gefunden wird, sucht Python in der Klasse.
Wenn wir jedoch zuweisen x.data , erstellt Python ein Attribut für das Objekt. Das Attribut der Klasse wird nicht ersetzt.
Dies ermöglicht uns die Objektinitialisierung . Python ruft die __init__Methode der Klasse bei neuen Instanzen automatisch auf, wenn sie erstellt werden, falls vorhanden. Bei dieser Methode können wir einfach Attribute zuweisen, um Anfangswerte für dieses Attribut für jedes Objekt festzulegen:
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
Jetzt müssen namewir ein angeben, wenn wir ein erstellen Example, und jede Instanz hat ihre eigene name. Python ignoriert das Klassenattribut, Example.namewenn wir das .nameeiner Instanz nachschlagen , da das Attribut der Instanz zuerst gefunden wird.
Eine letzte Einschränkung: Modifikation (Mutation) und Zuordnung sind verschiedene Dinge!
In Python sind Zeichenfolgen unveränderlich. Sie können nicht geändert werden. Wenn Sie das tun:
a = 'hi '
b = a
a += 'mom'
Sie ändern die ursprüngliche 'Hi'-Zeichenfolge nicht. Das ist in Python unmöglich. Stattdessen erstellen Sie eine neue Zeichenfolge 'hi mom'und veranlassen a, kein Name mehr zu sein 'hi ', und beginnen 'hi mom'stattdessen , ein Name für zu sein. Wir haben auch beinen Namen für erstellt 'hi 'und nach dem erneuten Anwenden des aNamens bist er immer noch ein Name für 'hi ', da er 'hi 'noch vorhanden ist und nicht geändert wurde.
Listen können jedoch geändert werden:
a = [1, 2, 3]
b = a
a += [4]
Jetzt bist auch [1, 2, 3, 4], weil wir beinen Namen für dasselbe gemacht haben, das abenannt wurde, und dann haben wir dieses Ding geändert. Wir haben keine neue Liste für aden Namen erstellt, da Python +=für Listen einfach anders behandelt .
Dies ist für Objekte von Bedeutung, da die Änderung in allen anderen Instanzen "gesehen" wird, wenn Sie eine Liste als Klassenattribut haben und eine Instanz zum Ändern der Liste verwenden. Dies liegt daran, dass (a) die Daten tatsächlich Teil des Klassenobjekts und kein Instanzobjekt sind; (b) Da Sie die Liste geändert und keine einfache Zuweisung vorgenommen haben, haben Sie kein neues Instanzattribut erstellt, das das Klassenattribut verbirgt.