Verständnisproblem mit global und import

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Verständnisproblem mit global und import

Beitragvon numerix » Mittwoch 19. November 2008, 22:04

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



Code: Alles auswählen

import counter

print counter.n
counter.count()
print counter.n


Liefert wie erwartet erst 0 und dann 1.

Code: Alles auswählen

from counter import *

print n
count()
print n


Liefert - für mich unerwartet - beidesmal 0.
DasIch
User
Beiträge: 2423
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Beitragvon DasIch » Mittwoch 19. November 2008, 22:24

Das hat mit global nichts zu tun. Du kopierst durch den import alles aus counter in den Namespace von __main__ aber die Funktion arbeitet deswegen noch lange nicht in dem Namespace von __main__.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Beitragvon yipyip » Mittwoch 19. November 2008, 22:26

DAS Problem kenn' ich,
guck mal hier:
http://www.python-forum.de/topic-16020.html?highlight=
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Mittwoch 19. November 2008, 22:46

@yipyip: Danke für den Link! Insbesondere der Beitrag von BlackJack in diesem Thread hat ein Stück weitergeholfen.

@DasIch: Das mit dem "kopieren" ist so eine Sache. Sieh dir das mal an:

Code: Alles auswählen

# changer.py
d = {}

def change():
    d["key"] = "value"



Code: Alles auswählen

from changer import *

print d
change()
print d


Liefert:

Code: Alles auswählen

{}
{'key': 'value'}


Ich verstehe es so: Beim Import eines Moduls werden Kopien aller Objekte auf Modulebene (des importieren Moduls) angelegt, sofern es sich um unveränderbare Objekte handelt; es existiert dann ein neues Objekt mit diesem Namen.
Sind es hingegegen veränderbare Objekte, wird statt einer Kopie eine Referenz angelegt.

Richtig?
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Beitragvon Trundle » Mittwoch 19. November 2008, 22:54

Es ist immer eine Referenz, nur manche Objekte sind eben nicht veränderbar. Wird im Modul ein anderes Objekt an einen bestimmten Namen gebunden, zeigt die Referenz im anderen Modul, das diesen Namen importiert hat, eben immer noch auf das andere (also "alte") Objekt.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
DasIch
User
Beiträge: 2423
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Beitragvon DasIch » Mittwoch 19. November 2008, 22:55

numerix hat geschrieben:Richtig?

Scheint so.

Auf jedenfall würde ich sagen dass man soetwas einfach vermeiden sollte.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Mittwoch 19. November 2008, 23:05

DasIch hat geschrieben:Auf jedenfall würde ich sagen dass man soetwas einfach vermeiden sollte.


ACK!
BlackJack

Beitragvon BlackJack » Mittwoch 19. November 2008, 23:07

@numerix: Python kopiert keine Objekte wenn man das nicht explizit will, und macht da auch keinen Unterschied zwischen veränderbaren und nicht veränderbaren Objekten.

Der Unterschied ist einfach ob man ein Objekt verändert, oder einen Namen an ein neues Objekt bindet.

In dem Sternchenimport-Beispiel wird zuerst `counter.n` an das Objekt 0 gebunden, dann werden durch das ``import`` im aktuellen Modul alle Objekt aus `counter` an gleichlautende Namen im aktuellen Modul gebunden. Das `n` aus dem aktuellen Modul wird ausgegeben. Beim Funktionsaufruf wird `counter.n` an ein neues Objekt (1) gebunden. Was natürlich nichts an der Bindung von `n` im aktuellen Modul an das 0-Objekt ändert. Und das wird dann noch einmal ausgegeben.

Unterschied beim Dictionary ist, dass Du das Dictionary-Objekt veränderst und natürlich diese Änderung überall sichtbar ist, wo dieses Objekt an einen Namen gebunden ist. Nach dem Aufruf der Funktion sind ja weiterhin sowohl `changer.d` als auch das "Lokale" `d` an das *selbe* Objekt gebunden.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Mittwoch 19. November 2008, 23:24

BlackJack hat geschrieben:@numerix: Python kopiert keine Objekte wenn man das nicht explizit will, und macht da auch keinen Unterschied zwischen veränderbaren und nicht veränderbaren Objekten.


Das verstehe ich jetzt nicht bzw. anscheinend habe ich bisher etwas falsch verstanden:

Code: Alles auswählen

a = 5
b = a # int ist immutable -> Kopie von a wird erzeugt
c = ["nix"]
d = c # list ist mutable -> Referenz von c wird erzeugt


Was passiert hier, wenn nicht das, was die Kommentare sagen?

Über den Rest muss ich morgen nochmal in Ruhe nachdenken ... :?
BlackJack

Beitragvon BlackJack » Mittwoch 19. November 2008, 23:39

Warum sollte da eine Kopie von `a` erzeugt werden? In beiden Fällen werden einfach nur je zwei Namen an das selbe Objekt gebunden. Die Situation sieht nach dem Ausführen so aus:

Code: Alles auswählen

 Namen |  Objekte
       |
  a----------->+-------+
       |       |<int> 5|
  b----------->+-------+
       |
  c----------->+--------+            +-----------+
       |       |<list> o+----------->|<str> "nix"|
  d----------->+--------+            +-----------+
       |
       |
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Beitragvon str1442 » Mittwoch 19. November 2008, 23:49

Code: Alles auswählen

In [1]: a = 5

In [2]: b = a

In [3]: a is b
Out[3]: True

In [4]: a += 1

In [5]: a, b
Out[5]: (6, 5)


Es sieht nur so aus, als würde eine Kopie erzeugt. Du operierst ja auf den Referenzen, und wenn du eine neu bindest, berührt das die andere nicht, die dann weiterhin auf das alte Objekt zeigt.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Beitragvon Darii » Donnerstag 20. November 2008, 13:14

numerix hat geschrieben:Was passiert hier, wenn nicht das, was die Kommentare sagen?


Um den Sachverhalt mal zu verdeutlichen:

Code: Alles auswählen

a += 1 # und
a["key"] += 1

sind zwei verschiedene Ausdrücke. Das erste ist äquivalent zu:

Code: Alles auswählen

a = a + 1

das zweite zu

Code: Alles auswählen

a.__setitem__("key", a["key"] + 1)


Im ersten Fall bindest du an den Namen a ein Objekt(was meist ein neues Objekt sein wird) während du im zweiten Fall den Namen a in Ruhe lässt.[/code]
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Donnerstag 20. November 2008, 20:57

Danke an euch, dass ihr euch so bemüht, mir das verständlich zu machen.
Ich glaube, so richtige gefressen hab ich es noch nicht.

Meine bisherige Vorstellung, was bei der Zuweisung an eine Variable in Abhängigkeit vom Datentyp passiert, halte ich nach wie vor für tragfähig und es schmerzt mich, dass das - trotz der Richtigkeit bezogen auf das Resultat - dennoch anscheinend nicht das ist, was tatsächlich passiert.

Meine Sicht war (und ist es momentan noch, bis ich das richtige Verständnis für mich tragfähig habe):
Beim Binden eines unveränderlichen Objekts an einen neuen Namen wird eine Kopie des Objekts erzeugt; beide Namen verweisen auf identische Objekte, die aber je eine eigene Identität haben (darum passt für mich er Begriff der "Kopie" an dieser Stelle), so dass Änderungen an einem der Objekte sich nicht auf das andere auswirken.

Beim Binden eines veränderlichen Objekts an einen neuen Namen wird nur eine neue Referenz auf das gleiche Objekt angelegt; es gibt nach wie vor nur ein einziges Objekt mit einer einzigen Identität. Änderungen an diesem einen Objekt sind über jeden Namen möglich, an den das eine Objekt gebunden ist.

Auch wenn es - wie BlackJack sagt (und ich gehe einfach mal davon aus, dass das so korrekt ist) - keine Kopie ist, so ist das Verhalten doch so, wie man es von einer Kopie erwarten würde.

Entsprechend habe mir auch die Parameterübergabe bei Funktionen vorgestellt: Als Wertparameter bei unveränderlichen Datentypen und als Referenzparameter bei veränderlichen Datentypen.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Beitragvon Trundle » Donnerstag 20. November 2008, 21:14

Dann lass dir doch einfach einmal die Identitäten der Objekte ausgeben (mit `id()`), dann wirst du sehen, dass es die selben Objekte sind. Außerdem, warum sollten denn von unveränderlichen Objekten überhaupt Kopien erstellt werden? Schließlich sind sie ja unveränderlich. Und wie soll Python feststellen, ob ein Typ unveränderlich ist oder nicht?
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Beitragvon str1442 » Donnerstag 20. November 2008, 21:17

Kannst du C?

Ich kann es zwar nur rudimentär, aber es lässt sich in etwa so veranschaulichen:

Code: Alles auswählen



int eins = 1;
int zwei = 2;
int drei = 3;

...

int *name_a = &eins;
int *name_b = &eins;

// Neu binden bei name_a++

name_a = &zwei

// name_b bleibt weiterhin &eins

(Gibts eigentlich einen Unterschied zwischen int* name und int *name? Müsste doch beides einen Zeiger erzeugen...)

Es ist wie bei einem Bücherregal. Du linkst mit einer Referenz auf ein Buch. Mit einer zweiten wieder zur grade angelegten. Intern wird beides Mal aufs gleiche Buch gelinkt.

Wenn du jetzt das Nachfolgende Buch bekommen willst, bindest du den Namen neu. Die alte Referenz wird aufgelöst und du bekommst eine neue auf das neue Buch. Die andere Referenz berührt das nicht.

Der Unterschied zum kopieren ist, das den Büchern deine Referenzen egal sind. Die existieren trotzdem weiter, auch wenn niemand auf sie referiert. [1] Bei einem veränderlichen Objekt änderst du ja nicht die Referenz zum eigentlichen Ding; nur die Interna eben dieses Objekts. Bei dem Bücherbeispiel wäre das zum Beispiel ein Regal. Das ändert seinen Ort ja auch nicht, wenn man ein Buch reinstellt.

[1] In Python werden Objekte natürlich vom gc vernichtet, wenn niemand mehr auf sie referiert. Trotzdem bleiben die Objekte theoretisch, einmal instanziert, immer die gleichen.

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder