Einführung
In diesem Abschnitt werden weitere Details über das interne Objektmodell von Python vorgestellt und einige Aspekte der Arbeitsspeicherverwaltung, Kopieren und Typüberprüfung diskutiert.
This tutorial is from open-source community. Access the source code
💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken
In diesem Abschnitt werden weitere Details über das interne Objektmodell von Python vorgestellt und einige Aspekte der Arbeitsspeicherverwaltung, Kopieren und Typüberprüfung diskutiert.
Viele Operationen in Python beziehen sich auf das Zuweisen oder Speichern von Werten.
a = value ## Zuweisung an eine Variable
s[n] = value ## Zuweisung an eine Liste
s.append(value) ## Anhängen an eine Liste
d['key'] = value ## Hinzufügen zu einem Wörterbuch
Achtung: Zuweisungsoperationen machen niemals eine Kopie des zugewiesenen Werts. Alle Zuweisungen sind lediglich Referenzkopien (oder Zeigerkopien, wenn Sie das bevorzugen).
Betrachten Sie diesen Codeausschnitt.
a = [1,2,3]
b = a
c = [a,b]
Ein Diagramm der zugrunde liegenden Arbeitsspeicheroperationen. In diesem Beispiel gibt es nur ein Listenobjekt [1,2,3]
, aber vier unterschiedliche Referenzen darauf.
Dies bedeutet, dass das Ändern eines Werts alle Referenzen beeinflusst.
>>> a.append(999)
>>> a
[1,2,3,999]
>>> b
[1,2,3,999]
>>> c
[[1,2,3,999], [1,2,3,999]]
>>>
Bemerken Sie, wie eine Änderung in der ursprünglichen Liste überall sonst sichtbar wird (auweia!). Dies liegt daran, dass keine Kopien gemacht wurden. Alles verweist auf das gleiche Objekt.
Das Umsetzen eines Werts überschreibt niemals den von dem vorherigen Wert verwendeten Arbeitsspeicher.
a = [1,2,3]
b = a
a = [4,5,6]
print(a) ## [4, 5, 6]
print(b) ## [1, 2, 3] Behält den ursprünglichen Wert bei
Denken Sie daran: Variablen sind Namen, nicht Arbeitsspeicheradressen.
Wenn Sie nicht über diese Teilung Bescheid wissen, werden Sie sich irgendwann selbst in den Fuß schießen. Typischer Szenario: Sie ändern einige Daten, denken dabei, dass es eine private Kopie ist, und versehentlich beschädigen Sie so Daten in einem anderen Teil des Programms.
Anmerkung: Dies ist einer der Gründe, warum die primitiven Datentypen (int, float, string) unveränderlich (schreibgeschützt) sind.
Verwenden Sie den is
-Operator, um zu überprüfen, ob zwei Werte genau dasselbe Objekt sind.
>>> a = [1,2,3]
>>> b = a
>>> a is b
True
>>>
is
vergleicht die Objektidentität (eine Ganzzahl). Die Identität kann mit id()
abgerufen werden.
>>> id(a)
3588944
>>> id(b)
3588944
>>>
Hinweis: Es ist fast immer besser, ==
zum Überprüfen von Objekten zu verwenden. Verhalten von is
ist oft unerwartet:
>>> a = [1,2,3]
>>> b = a
>>> c = [1,2,3]
>>> a is b
True
>>> a is c
False
>>> a == c
True
>>>
Listen und Dictionaries haben Methoden zum Kopieren.
>>> a = [2,3,[100,101],4]
>>> b = list(a) ## Mach eine Kopie
>>> a is b
False
Es ist eine neue Liste, aber die Listenelemente werden geteilt.
>>> a[2].append(102)
>>> b[2]
[100,101,102]
>>>
>>> a[2] is b[2]
True
>>>
Zum Beispiel wird die innere Liste [100, 101, 102]
geteilt. Dies ist eine flache Kopie. Hier ist ein Diagramm.
Manchmal müssen Sie eine Kopie eines Objekts und aller darin enthaltenen Objekte erstellen. Hierfür können Sie das copy
-Modul verwenden:
>>> a = [2,3,[100,101],4]
>>> import copy
>>> b = copy.deepcopy(a)
>>> a[2].append(102)
>>> b[2]
[100,101]
>>> a[2] is b[2]
False
>>>
Variablennamen haben keinen Typ. Es ist lediglich ein Name. Werte hingegen haben einen zugrunde liegenden Typ.
>>> a = 42
>>> b = 'Hello World'
>>> type(a)
<type 'int'>
>>> type(b)
<type 'str'>
type()
wird Ihnen sagen, was es ist. Der Typname wird normalerweise als Funktion verwendet, die einen Wert erstellt oder in diesen Typ umwandelt.
Wie man herausfindet, ob ein Objekt vom angegebenen Typ ist.
if isinstance(a, list):
print('a ist eine Liste')
Überprüfung auf einen von mehreren möglichen Typen.
if isinstance(a, (list,tuple)):
print('a ist eine Liste oder ein Tupel')
*Vorsicht: Machen Sie nicht zu viel Typüberprüfung. Dies kann zu einer übermäßigen Codekomplexität führen. Normalerweise würden Sie dies nur tun, wenn dadurch häufige Fehler anderer, die Ihr Code verwenden, vermieden werden können.
Zahlen, Zeichenketten, Listen, Funktionen, Ausnahmen, Klassen, Instanzen usw. sind alle Objekte. Das bedeutet, dass alle benannten Objekte als Daten weitergegeben, in Containern platziert usw. werden können, ohne Einschränkungen. Es gibt keine besondere Arten von Objekten. Manchmal wird gesagt, dass alle Objekte "erstklassig" sind.
Ein einfaches Beispiel:
>>> import math
>>> items = [abs, math, ValueError ]
>>> items
[<built-in function abs>,
<module'math' (builtin)>,
<type 'exceptions.ValueError'>]
>>> items[0](-45)
45
>>> items[1].sqrt(2)
1.4142135623730951
>>> try:
x = int('not a number')
except items[2]:
print('Fehlgeschlagen!')
Fehlgeschlagen!
>>>
Hier ist items
eine Liste, die eine Funktion, ein Modul und eine Ausnahme enthält. Man kann die Elemente in der Liste direkt anstelle der ursprünglichen Namen verwenden:
items[0](-45) ## abs
items[1].sqrt(2) ## math
except items[2]: ## ValueError
Mit großer Macht kommt große Verantwortung. Nur weil man das kann, heißt nicht, dass man es sollte.
In dieser Übungsgruppe betrachten wir einige der Möglichkeiten, die aus erstklassigen Objekten resultieren.
In der Datei portfolio.csv
lesen wir Daten, die in Spalten organisiert sind und so aussehen:
name,shares,price
"AA",100,32.20
"IBM",50,91.10
...
In früherem Code haben wir das csv
-Modul verwendet, um die Datei zu lesen, mussten aber immer noch manuelle Typumwandlungen vornehmen. Beispielsweise:
for row in rows:
name = row[0]
shares = int(row[1])
price = float(row[2])
Diese Art der Umwandlung kann auch auf eine cleverere Weise mit einigen Listenbasisoperationen durchgeführt werden.
Erstellen Sie eine Python-Liste, die die Namen der Umwandlungsfunktionen enthält, die Sie verwenden würden, um jede Spalte in den entsprechenden Typ umzuwandeln:
>>> types = [str, int, float]
>>>
Der Grund, warum Sie diese Liste sogar erstellen können, ist, dass alles in Python erstklassig ist. Also, wenn Sie eine Liste von Funktionen haben möchten, ist das kein Problem. Die Elemente in der von Ihnen erstellten Liste sind Funktionen zum Konvertieren eines Werts x
in einen bestimmten Typ (z.B. str(x)
, int(x)
, float(x)
).
Lesen Sie jetzt eine Zeile von Daten aus der obigen Datei:
>>> import csv
>>> f = open('portfolio.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> row = next(rows)
>>> row
['AA', '100', '32.20']
>>>
Wie erwähnt, reicht diese Zeile nicht aus, um Berechnungen durchzuführen, weil die Typen falsch sind. Beispielsweise:
>>> row[1] * row[2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type'str'
>>>
Allerdings kann die Daten vielleicht mit den Typen, die Sie in types
angegeben haben, zusammengeführt werden. Beispielsweise:
>>> types[1]
<type 'int'>
>>> row[1]
'100'
>>>
Versuchen Sie, einen der Werte zu konvertieren:
>>> types[1](row[1]) ## Gleiches wie int(row[1])
100
>>>
Versuchen Sie, einen anderen Wert zu konvertieren:
>>> types[2](row[2]) ## Gleiches wie float(row[2])
32.2
>>>
Versuchen Sie die Berechnung mit den konvertierten Werten:
>>> types[1](row[1])*types[2](row[2])
3220.0000000000005
>>>
Zip die Spaltentypen mit den Feldern und betrachten Sie das Ergebnis:
>>> r = list(zip(types, row))
>>> r
[(<type'str'>, 'AA'), (<type 'int'>, '100'), (<type 'float'>,'32.20')]
>>>
Sie werden feststellen, dass dies einen Typumwandlung mit einem Wert zusammengeführt hat. Beispielsweise ist int
mit dem Wert '100'
zusammengeführt.
Die zusammengefügte Liste ist nützlich, wenn Sie alle Werte nacheinander umwandeln möchten. Versuchen Sie das:
>>> converted = []
>>> for func, val in zip(types, row):
converted.append(func(val))
...
>>> converted
['AA', 100, 32.2]
>>> converted[1] * converted[2]
3220.0000000000005
>>>
Stellen Sie sicher, dass Sie verstehen, was im obigen Code passiert. In der Schleife ist die Variable func
eine der Typumwandlungsfunktionen (z.B. str
, int
usw.) und die Variable val
ist einer der Werte wie 'AA'
, '100'
. Der Ausdruck func(val)
konvertiert einen Wert (ähnlich wie eine Typumwandlung).
Den obigen Code kann in eine einzelne Listenkomprehension komprimiert werden.
>>> converted = [func(val) for func, val in zip(types, row)]
>>> converted
['AA', 100, 32.2]
>>>
Denken Sie daran, wie die dict()
-Funktion ein Dictionary leicht erstellen kann, wenn Sie eine Sequenz von Schlüsselnamen und Werten haben? Lassen Sie uns ein Dictionary aus den Spaltenüberschriften erstellen:
>>> headers
['name','shares', 'price']
>>> converted
['AA', 100, 32.2]
>>> dict(zip(headers, converted))
{'price': 32.2, 'name': 'AA','shares': 100}
>>>
Natürlich, wenn Sie Ihre Fähigkeiten bei der Verwendung von Listenkomprehensions beherrschen, können Sie die gesamte Umwandlung in einem Schritt mit einer Dictionary-Komprehension vornehmen:
>>> { name: func(val) for name, func, val in zip(headers, types, row) }
{'price': 32.2, 'name': 'AA','shares': 100}
>>>
Mit den Techniken aus dieser Übung könnten Sie Anweisungen schreiben, die Felder aus fast jedem spaltenorientierten Datenfile leicht in ein Python-Dictionary umwandeln.
Nur zur Veranschaulichung: Nehmen wir an, Sie lesen Daten aus einer anderen Datendatei wie folgt:
>>> f = open('dowstocks.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> row = next(rows)
>>> headers
['name', 'price', 'date', 'time', 'change', 'open', 'high', 'low', 'volume']
>>> row
['AA', '39.48', '6/11/2007', '9:36am', '-0.18', '39.67', '39.69', '39.45', '181800']
>>>
Lassen Sie uns die Felder mit einem ähnlichen Trick umwandeln:
>>> types = [str, float, str, str, float, float, float, float, int]
>>> converted = [func(val) for func, val in zip(types, row)]
>>> record = dict(zip(headers, converted))
>>> record
{'volume': 181800, 'name': 'AA', 'price': 39.48, 'high': 39.69,
'low': 39.45, 'time': '9:36am', 'date': '6/11/2007', 'open': 39.67,
'change': -0.18}
>>> record['name']
'AA'
>>> record['price']
39.48
>>>
Bonus: Wie würden Sie dieses Beispiel modifizieren, um den date
-Eintrag zusätzlich in ein Tupel wie (6, 11, 2007)
zu parsen?
Nehmen Sie sich ein wenig Zeit, um über das Nachdenken, was Sie in dieser Übung gemacht haben. Wir werden diese Ideen ein wenig später noch einmal aufgreifen.
Herzlichen Glückwunsch! Sie haben das Objekte-Labor abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.