Verständnisproblem mit global und import
@Darii: Ich schreib den "Stern" immer zum Namen weil sonst so etwas wie ``int* foo, bar;`` (noch) leichter falsch verstanden werden kann.
Mal generell:numerix hat geschrieben:Wäre nett, wenn mir jemand folgendes Verhalten erklären könnte.
Code: Alles auswählen
# counter.py n = 0 def count(): global n n += 1
Liefert wie erwartet erst 0 und dann 1.Code: Alles auswählen
import counter print counter.n counter.count() print counter.n
Liefert - für mich unerwartet - beidesmal 0.Code: Alles auswählen
from counter import * print n count() print n
Man sollte zwischen Bezeichnern, Objekten und deren Referenzen unterscheiden.
Variablen sind Bezeichner für Referenzen, mehr nicht.
"=" Statements sind Definitionen, die einem Bezeichner links vom "=" eine Referenz rechts vom "=" zuweisen. Die Referenz wird hierbei vom Python Environment gemanaged:
Steht zb. rechts auch ein Bezeichner, wird dessen Referenz verwendet, steht dort ein Objekt, wird dort eine Referenz erzeugt, indem ein neues Objekt mit neuer Referenz verwendet wird; dies ist völlig unabhängig davon, ob das Objekt "mutable" ist oder nicht (wobei Referenzen bestehender immutable Objekte hierbei präferiert werden). Für gewisse Objekte wie bei "class" und "def" werden automatisch Bezeichner mit den entsprechenden Referenzen erzeugt, und das zur "Compilezeit" und nicht erst zur Laufzeit! D.h. zB bei Definitionen von Funktionen, dass auch deren Parameter zur Compilzeit schon an Objektreferenzen "gebunden" werden. Sind dies "mutable" Objekte, kann die Vorbelegung der Parameter bei jedem Aufruf ein geändertes Objekt bedeuten!
Die Bezeichner haben eine weitere wichtig Eigenschaft: Namensraum.
Die Sichtbarkeit von Bezeichnern ist "user-managed", d.h. der Programmierer kann Einfluss darauf nehmen, indem er Bezeichner entsprechend klassifiziert (zB mit "global") oder explizit externe Namensräume einbindet (zB über "import"). Dies geschieht ebenfalls zur Compilezeit! Er kann auch Bezeichner aus einem Namensraum entfernen (zB mit "del"); hierbei hat er jedoch keinen Einfluss auf die Speicherallokation der Objekte, diese wird ausschliesslich vom Python Environment gemanaged (GC mittels Referenzcounter).
Okay, was mach dein "global" nun in counter.py:
Es bindet den Bezeichner "n" im Namensraum von "counter" in den lokalen Namensraum von "count" ein. Das zur Compilezeit!
Jede Änderung von "n" in diesem Namensraum ist somit eine Änderung der Referenz von "counter.n".
Was machen nun deine Beispiele:
"import counter" bindet den Bezeichner "counter", der "counter.py" referenziert, in den lokalen Namensraum von "__main__" ein.
Deine "print" Ausgaben sind durch "counter.n" referenziert, also genau die Bezeichner, auf die "counter.count" zugreifft. Alles okay.
"from counter import *" bindet die Bezeichner "n" und "count" in den lokalen Namensraum ein. "n" hält hierbei die gleiche Referenz wie "counter.n".
Deine "print" Ausgaben sind durch "n" referenziert, "count" jedoch operiert im Namensraum "counter.n" mit "n". D.h. die Referenz von "counter.n" ist nicht mehr gleich der von "n", das immer noch seine ursprüngliche Referenz hält (zum Zeitpunkt vom import)
Welche Möglichkeiten hat man, im Namensraum von "__main__" die Referenz von "n" durch "counter.count" zu ändern?
Zwei Beispiele, die jetzt verständlich sein sollten:
Code: Alles auswählen
import counter
from counter import *
print n
count()
n = counter.n
print n
Code: Alles auswählen
### counter.py
n = [0]
def count():
global n
n[0] += 1
###
from counter import *
print n[0]
count()
print n[0]
Zuletzt geändert von Qubit am Freitag 21. November 2008, 13:35, insgesamt 1-mal geändert.
Hi,
gibt es hier vllt. eine Analogie zu dem Linuxbefehl?
Also ein Hardlink (link) hat soweit ich weiß ja die selbe Inode Nummer wie
die Datei auf die er zeigt ist jedoch nur ein weiterer Name für die Datei.
Ein Softlink (link -s) hat aber doch eine eigene Inodenummer und zeigt wirklich nur auf die Datei, d.h. wenn man ihn anklickt öffnet man eigentlich die Datei auf die er zeigt.
MfG Jonas
gibt es hier vllt. eine Analogie zu dem Linuxbefehl
Code: Alles auswählen
link [-s]
Also ein Hardlink (link) hat soweit ich weiß ja die selbe Inode Nummer wie
die Datei auf die er zeigt ist jedoch nur ein weiterer Name für die Datei.
Ein Softlink (link -s) hat aber doch eine eigene Inodenummer und zeigt wirklich nur auf die Datei, d.h. wenn man ihn anklickt öffnet man eigentlich die Datei auf die er zeigt.
MfG Jonas
Das stimmt zwar, ist aber leicht verwirrend, da du ja kein Objekt ohne Bezeichner schreiben kannst, es sei denn, es wird durch eine Aktion (Aufrufen, mehrere Objekte bauen irgendwas, was auch immer) erzeugt.Steht zb. rechts auch ein Bezeichner, wird dessen Referenz verwendet, steht dort ein Objekt, wird dort eine Referenz erzeugt, indem ein neues Objekt mit neuer Referenz verwendet wird
@jonas:
Statt link verwende besser "ln", das hat mehr Funktionen, wird afaik öfter verwendet und kann links zwischen allem kreieren.
Außerdem hat bei mir link überhaupt keine "s" Option, und bekommt wohl nur Hardlinks hin.
- Rebecca
- User
- Beiträge: 1662
- Registriert: Freitag 3. Februar 2006, 12:28
- Wohnort: DN, Heimat: HB
- Kontaktdaten:
jonas: Frage lesen, welche BlackJack beantwortet hat Es gibt eine Analogie zu link, nicht zu link -s.
Offizielles Python-Tutorial (Deutsche Version)
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
@Qubit: Danke auch an dich für die ausführliche Behandlung des Ausgangsproblems. Um sicher zu gehen, dass ich auch das jetzt verstanden habe, nochmal mit meinen Worten:
Durch den import wird im globalen Namensraum von test.py eine Referenz auf n und count im Modul counter.py angelegt, d.h. zwei die Namen n und count werden an diese beiden Objekte aus counter.py gebunden. Beim Aufruf von count() wird also das Objekt count aus counter.py aufgerufen. Im lokalen Namensraum von count() wird der Bezeichner n als globaler Bezeichner (des Moduls counter.py) deklariert und damit die Möglichkeit eröffnet, an den globalen Bezeichner n innerhalb des lokalen Namensraums von count() ein neues Objekt zu binden. Genau dies geschieht dann durch die Zuweisung "n+=1": Der Name n wird neu an ein Objekt gebunden (und nicht der Wert des Objekts um 1 erhöht!). Ab diesem Zeitpunkt ist das n in counter.py nicht mehr das n in test.py, welches nämlich nach wie vor an das gleiche Objekt (nämlich die 0) gebunden ist.
Richtig?
Code: Alles auswählen
# counter.py
n = 0
def count():
global n
n += 1
Code: Alles auswählen
# test.py
from counter import *
print n
count()
print n
Richtig?
Ja! Genau so sehe ich das..numerix hat geschrieben: Durch den import wird im globalen Namensraum von test.py eine Referenz auf n und count im Modul counter.py angelegt, d.h. zwei die Namen n und count werden an diese beiden Objekte aus counter.py gebunden. Beim Aufruf von count() wird also das Objekt count aus counter.py aufgerufen. Im lokalen Namensraum von count() wird der Bezeichner n als globaler Bezeichner (des Moduls counter.py) deklariert und damit die Möglichkeit eröffnet, an den globalen Bezeichner n innerhalb des lokalen Namensraums von count() ein neues Objekt zu binden. Genau dies geschieht dann durch die Zuweisung "n+=1": Der Name n wird neu an ein Objekt gebunden (und nicht der Wert des Objekts um 1 erhöht!). Ab diesem Zeitpunkt ist das n in counter.py nicht mehr das n in test.py, welches nämlich nach wie vor an das gleiche Objekt (nämlich die 0) gebunden ist.
Richtig?
Kannst du mir erklären, was für eine Logik dahintersteckt?BlackJack hat geschrieben:@Darii: Ich schreib den "Stern" immer zum Namen weil sonst so etwas wie ``int* foo, bar;`` (noch) leichter falsch verstanden werden kann.
Ich weiss nicht ob ich die Frage richtig verstehe. Der Stern gehört zum Namen. ``int* foo, bar;`` kann leicht fehlinterpretiert werden, als dass `foo` und `bar` beide vom Typ "Zeiger auf `int`" sind, wo doch nur `foo` diesen Typ hat und `bar` ein normales `int` ist. Wenn beides Zeiger sein sollen müsste es ``int *foo, *bar;`` lauten.
Ja hast du danke. Ich dachte, dass das * zum Typ gehört(wie es eigentlich auch naheliegend und konsequent wäre).BlackJack hat geschrieben:Ich weiss nicht ob ich die Frage richtig verstehe.
Code: Alles auswählen
int **foo = new int* // Bei new gehört das Sternchen auf einmal zum Typ
Kommt doch aufs selbe hinausLeonidas hat geschrieben:Seit wann hat C ein ``new``?
Code: Alles auswählen
int **foo = malloc(sizeof(int*))