Python-Variablendeklaration

85

Python lernen und hat einige grundlegende Zweifel.

1.Ich habe die Variablendeklaration (Pfad hier) als gesehen

class writer:
    path = ""

manchmal keine explizite Deklaration sondern durch initialisieren __init__.

def __init__(self, name):
    self.name = name

Ich verstehe den Zweck von __init__, aber es ist ratsam, Variable in anderen Funktionen zu deklarieren.

2.Wie kann ich eine Variable für einen benutzerdefinierten Typ erstellen?

class writer:
    path = "" # string value
    customObj = ??
bsr
quelle
12
Und in Bezug auf die zweite Frage: In Python haben Variablen keinen Typ: Werte. So kann jede Variable Ihre benutzerdefinierten Objekte enthalten.
Jpaugh
4
Es ist hilfreich, wenn Sie aufhören, Namen / IDendifiers als Variablen zu betrachten . Sie sind Verweise auf Objekte
John La Rooy
2
@gnibbler Oder Namen für sie ...
Detly
1
@detly, ich denke, Namen sind eine schlechte Wahl. Dinge haben normalerweise nur einen Namen, während ein Objekt mehrere Referenzen haben kann
John La Rooy
2
@ JohnClements, aber Python funktioniert nicht wie Mathe. Wenn Sie Python verstehen möchten, müssen Sie wissen, dass Objekte mit einem __name__Attribut einen "Namen" haben. Nicht alle Objekte haben ein __name__Attribut, aber Sie können trotzdem Verweise darauf haben. Wenn wir anfangen, eine "Referenz" als "Namen" zu bezeichnen, tun wir Anfängern einen schlechten Dienst.
John La Rooy

Antworten:

202

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.

Karl Knechtel
quelle
12
Deshalb nennen wir sie "Bezeichner" . :-)
Martijn Pieters
@Karl_Knechtel in Ihrem String-Beispiel am Ende, was passiert mit 'hi', wenn wir es nie als 'b' bezeichnen? Ist das ein Speicherverlust?
Heretoinfinity
2
@heretoinfinity: nein; Python verwendet Garbage Collection, um nicht erreichbare Objekte
John Clements
Die Variablendeklaration wird in diesem Video gut erklärt: youtube.com/watch?v=ao2N37E-D9s .
Ishaq Khan
In diesem Video finden Sie die Antwort youtube.com/…
Thao N
22

In Python müssen keine neuen Variablen deklariert werden. Wenn es sich um Variablen in Funktionen oder Modulen handelt, ist keine Deklaration erforderlich. Weisen Sie einem Namen einfach einen Wert zu, wo Sie ihn benötigen : mymagic = "Magic". Variablen in Python können Werte eines beliebigen Typs enthalten, und Sie können dies nicht einschränken.

Ihre Frage fragt jedoch speziell nach Klassen, Objekten und Instanzvariablen. Die idiomatische Methode zum Erstellen von Instanzvariablen liegt in der __init__Methode und nirgendwo anders. Sie können zwar neue Instanzvariablen in anderen Methoden oder sogar in nicht verwandtem Code erstellen, dies ist jedoch nur eine schlechte Idee. Es wird Ihren Code schwer machen, darüber nachzudenken oder ihn zu pflegen.

Also zum Beispiel:

class Thing(object):

    def __init__(self, magic):
        self.magic = magic

Einfach. Jetzt haben Instanzen dieser Klasse ein magicAttribut:

thingo = Thing("More magic")
# thingo.magic is now "More magic"

Das Erstellen von Variablen im Namespace der Klasse selbst führt zu einem insgesamt unterschiedlichen Verhalten. Es ist funktional anders und Sie sollten es nur tun, wenn Sie einen bestimmten Grund dafür haben. Beispielsweise:

class Thing(object):

    magic = "Magic"

    def __init__(self):
        pass

Versuchen Sie jetzt:

thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1

Oder:

class Thing(object):

    magic = ["More", "magic"]

    def __init__(self):
        pass

thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]

Dies liegt daran, dass sich der Namespace der Klasse selbst vom Namespace der daraus erstellten Objekte unterscheidet. Ich überlasse es Ihnen, das etwas genauer zu untersuchen.

Die Nachricht zum Mitnehmen lautet, dass idiomatisches Python (a) Objektattribute in Ihrer __init__Methode initialisieren und (b) das Verhalten Ihrer Klasse nach Bedarf dokumentieren soll. Sie müssen sich nicht für alles, was Sie jemals schreiben, die Mühe machen, eine vollständige Dokumentation auf Sphinx-Ebene zu erstellen, sondern zumindest einige Kommentare zu den Details, die Sie oder jemand anderes möglicherweise benötigen, um sie zu erfassen.

detly
quelle
22

Dies kann 6 Jahre zu spät sein, aber in Python 3.5 und höher deklarieren Sie einen Variablentyp wie folgt:

variable_name: type_name

oder dieses:

variable_name # type: shinyType

In Ihrem Fall (wenn Sie eine CustomObjectKlasse definiert haben) können Sie Folgendes tun:

customObj: CustomObject

Siehe dies oder das für weitere Informationen.

O. Aroesti
quelle
12

Für Scoping-Zwecke verwende ich:

custom_object = None
redhot
quelle
1

Variablen haben einen Gültigkeitsbereich, daher ist es angemessen, Variablen zu haben, die für Ihre Funktion spezifisch sind. Sie müssen ihre Definition nicht immer explizit angeben. Normalerweise können Sie sie einfach verwenden. Nur wenn Sie etwas Spezifisches für den Typ der Variablen tun möchten, z. B. das Anhängen einer Liste, müssen Sie diese definieren, bevor Sie sie verwenden. Typisches Beispiel dafür.

list = []
for i in stuff:
  list.append(i)

Dies ist übrigens keine gute Möglichkeit, die Liste einzurichten. Es wäre besser zu sagen:

list = [i for i in stuff] # list comprehension

...Aber ich schweife ab.

Deine andere Frage. Das benutzerdefinierte Objekt sollte selbst eine Klasse sein.

class CustomObject(): # always capitalize the class name...this is not syntax, just style.
  pass
customObj = CustomObject()
ChipJust
quelle