Eigener Datentyp -> Globale Variable?

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.
Antworten
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Hey.
Warum ist das so?

Code: Alles auswählen

>>> class foo():
	    def __init__(self):
		    self.foo = 100

>>> a = foo()
>>> b = 100
>>> def bla():
	    a.foo = 10

>>> def blubb():
	    b = 10

>>> bla()
>>> a.foo
10
>>> blubb()
>>> b
100
BlackJack

@Nocta: Weil so halt die Scoping-Regeln von Python funktionieren. Wenn man irgendwo in einer Funktion (oder Methode) einen Namen bindet, ist der lokal.

In `bla()` veränderst Du das Objekt was an `a` gebunden ist und in `blubb()` bindest Du einen Wert an einen lokalen Namen `b`.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Hm okay.
Wenn das so ist, muss ich's wohl hinnehmen, auch wenn ich das seltsam finde :D
Ich dachte bisher immer, dass man in Funktionen zwar Variablen aus einer höheren Ebene lesen darf, aber nicht verändern kann.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Du veränderst ja nicht die "Variable a", schließlich ist das Objekt, das an den Namen 'a' gebunden ist ja vorher wie nachher das selbe. Du änderst lediglich ein Attribut, und das ist erlaubt.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Ja, der Unterschied zwischen dem, was ich mache ist mir klar.
Aber dass ich ein Objekt, welches sich eine Ebene über der Funktion befindet, innerhalb einer Funktion verändern kann, hat mich gewundert.

Aber so gesehn ist das Verhalten gar nicht mal schlecht. Wenn man auf objekt.attribut zugreift erhält man entweder einen Error, oder aber man greift auf ein Objekt zurück, welches auf einer höheren Ebene existiert.
Für mich ist das zwar ein bisschen zu "tolerant", weil das wieder teilweise globale Variablen bzw "globale Objektattribute" fördert, aber naja, man muss schließlich selbst wissen, wie man programmiert.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Es gibt sogar drei Namensräume, die man beachten muss: Den Lokalen, den Globalen und den Namensraum, der zur Definitionszeit im umliegenden Block aktiv war.

Code: Alles auswählen

>>> a, b, c = 1, 1, 1
>>> def outer():
...   b = 2
...   def inner():
...     c = 3
...     print a, b, c
...   return inner
... 
>>> inner = outer()
>>> inner()
1 2 3
Zum Glück haut einem Python aber einen Fehler um die Ohren, wenn man in einem Block aus versehen lokale und nicht-lokale variablen mit dem gleichen Namen verwendet. Das merkst du z.B. wenn du Zeile 5 und 6 in meinem Beispiel vertauscht.
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nocta hat geschrieben:Aber dass ich ein Objekt, welches sich eine Ebene über der Funktion befindet, innerhalb einer Funktion verändern kann, hat mich gewundert.
Naja, "Verändern" ist relativ:

Code: Alles auswählen

>>> class Foo(object): pass
... 
>>> foo = Foo()
>>> def modify_foo(): foo.bar = 42
... 
>>> id(foo)
3077101996L
>>> hasattr(foo, 'bar')
False
>>> modify_foo()
>>> foo.bar
42
>>> id(foo)
3077101996L
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Naja, für mich ist das verändert :D

Dass es kein neues Objekt ist, ist klar, weil das anscheinend das einzige ist, was nicht geht :)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nocta hat geschrieben:Naja, für mich ist das verändert :D

Dass es kein neues Objekt ist, ist klar, weil das anscheinend das einzige ist, was nicht geht :)
Das hier ist der Punkt, wo dein Verständnis von Variablen in Python zusammenbrechen sollte ;-) Du musst dir klar machen, was snafu schon versucht hat: den Unterschied zwischen "echten" Variablen und an Namen gebundene Objekte.
Das Leben ist wie ein Tennisball.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Und was ist dann eine "echte" Variable? ;)
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Nur damit das auch geklärt ist :twisted:

Code: Alles auswählen

>>> a = 100
>>> def blubb():
...     global a
...     a = 10
...     
>>> a
100
>>> blubb()
>>> a
10


verwenden solltest du global aber nicht, dass kann ganz schön schief gehen
Wenn man global braucht, ist es (meiner Meinung nach) Zeit für eine Klasse
the more they change the more they stay the same
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

"Echte Variable" ist doof gewählt. Es geht darum, ob ein neues Objekt an den Namen gebunden wurde oder ob Attribute des vorhandenen Objekts verändert wurden. Aber eigentlich erkennt man das ja auch durch Anschauen der Beispiele und Ausprobieren. Und du hast es auch selbst erkannt. :)
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Ja, das Verhalten hab ich mittlerweile erkannt.

Neues Objekt an den Namen binden: Nein
An den Namen gebundenes Objekt ändern: Ja

Das werd ich dann fortan als Tatsache ansehen, mich hat es halt etwas stutzig gemacht. Dass man Objekte von außerhalb lesen kann, war mir schon bekannt und steht an mehreren Stellen im Internet (auch hier im Forum). Aber da ist irgendwie nie die Rede davon, dass man das Objekt auch ändern (also die Attribute schreiben) kann.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Nocta hat geschrieben: Neues Objekt an den Namen binden: Nein
An den Namen gebundenes Objekt ändern: Ja
Soweit richtig.
Nocta hat geschrieben:Das werd ich dann fortan als Tatsache ansehen, mich hat es halt etwas stutzig gemacht. Dass man Objekte von außerhalb lesen kann, war mir schon bekannt und steht an mehreren Stellen im Internet (auch hier im Forum). Aber da ist irgendwie nie die Rede davon, dass man das Objekt auch ändern (also die Attribute schreiben) kann.
Eigentlich ist das 'ändern können' die Regel und das 'nicht ändern können' die Ausnahme. Objekte sind in Python nämlich grundsätzlich "mutable", also veränderbar. Integer, Floats, Strings, Tupel u.s.w. sind aber explizit 'immutable', also nicht veränderbar. Dieser Begriff, der auch oft in der Dokumentation vor kommt, ist in Python ziemlich wichtig.

Immutable bedeutet: Du kannst eine neue Version an den gleichen Namen binden, aber du kannst nicht den Wert selbst verändern. Darum bist du gezwungen, `a=1` statt `a.set(1)` zu schreiben.
Bottle: Micro Web Framework + Development Blog
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Okay, das leuchtet so weit ein.
Ich muss mich nur von dem Gedanken trennen, dass die Namensräume wie in anderen Sprachen funktionieren und mir deine Regel
Eigentlich ist das 'ändern können' die Regel
einprägen :)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Nocta hat geschrieben:Okay, das leuchtet so weit ein.
Ich muss mich nur von dem Gedanken trennen, dass die Namensräume wie in anderen Sprachen funktionieren und mir deine Regel
Die Namenräume funktionieren aber(größenteils) wie in anderen Sprachen.

Hier das Äquivalent in C zu deinem ersten Programm:

Code: Alles auswählen

#include <stdlib.h>
#include <stdio.h>

typedef struct {
  int foo;
} foo;

foo a = { .foo = 100 };
int b = 100;
void bla() {
  a.foo = 10;
}
void blubb() {
  int b = 10;
}

int main() {
  bla();
  printf("%d\n", a.foo); // 10
  blubb();
  printf("%d\n", b); // 100
  return EXIT_SUCCESS;
}
Produziert dieselbe Ausgabe wie die Python-Version.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Hm noch eine andere Frage:
Ist es schlechter Stil, dieses Verhalten zu benutzen?

Also einfach innerhalb einer Funktion auf ein Objekt außerhalb der Funktion zuzugreifen und zu verändern?
Das würde es mir zB ersparen, aufwendig die Rückgabe einer Funktion zu verarbeiten und mit dieser Rückgabe Objekte entsprechend zu verändern, oder mir sonst was einfallen zu lassen.
lunar

@Nocta: Kommt auf die Situation an …
BlackJack

@Nocta: Grundsätzlich würde ich aber schon sagen, dass das ein "code smell" ist.

Wobei wir vielleicht nochmal klären sollten was "auf ein Objekt ausserhalb der Funktion" bedeutet. Wo kommt das her? Wenn es als Argument übergeben wird, ist das was anderes als wenn der Zugriff fest in die Funktion einkodiert ist. Eine Funktion die Objekte entgegennimmt und deren Zustand verändert ist ziemlich normal. Solange das nicht an ein festes Exemplar gekoppelt ist, und das Verhalten dokumentiert oder offensichtlich ist, spricht da nichts gegen.

Ausser vielleicht, dass die Verantwortung der Änderung ganz oder teilweise beim Objekt liegen sollte. Das muss man aber für jeden konkreten Fall einzeln betrachten.
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Okay danke, ich denke das beantwortet meine Frage :)
Das Objekt wird als Parameter übergeben und es ist ist relativ ersichtlich, dass das Objekt geändert werden soll.
Antworten