Seite 1 von 1

Attribut als default-Parameter in Klassenmethode?

Verfasst: Dienstag 23. August 2005, 15:27
von N317V
Hi, zusammen!

Man kann ja in Python bei einer Funktions- bzw. Methodendefinition für einen Parameter einen default-Wert definieren. Aber

Code: Alles auswählen

class foo:
    
    def __init__(self):
        self.irgendwas = 'dingsbums'

    def methodeEins(self, parameter=self.irgendwas):
        sonstiger Code

bringt mir den Fehler "NameError: name 'self' is not defined". Irgendwer ne Idee, was da falsch ist oder wie man das lösen kann?

TIA

Greetings!

N317V

Verfasst: Dienstag 23. August 2005, 15:33
von jens
Vielleicht nicht ganz was du willst:

Code: Alles auswählen

class foo:
    irgendwas = 'dingsbums'

    def methodeEins(self, parameter=irgendwas):
        print parameter

Verfasst: Dienstag 23. August 2005, 15:41
von N317V
Lösung hab ich jetzt doch noch schnell gefunden:

Code: Alles auswählen

def methodeEins(self, parameter=None):
    if not parameter:
        parameter=self.irgendwas
Nicht unbedingt der Bringer, aber immerhin gehts. Trotzdem versteh ich nicht so ganz, warum das andere nicht funktioniert. Das hielte ich für wesentlich eleganter.

Verfasst: Dienstag 23. August 2005, 15:44
von mawe
Hi!

Deine Methode etwas abgewandelt:

Code: Alles auswählen

In [1]: class Foo:
   ...:     def __init__(self):
   ...:         self.var = "blabla"
   ...:     def methode(self, parameter=None):
   ...:         bla = parameter or self.var
   ...:         print bla
   ...:

In [2]: f = Foo()

In [3]: f.methode()
blabla

In [4]: f.methode("gaga")
gaga
Gruß, mawe

Verfasst: Dienstag 23. August 2005, 16:02
von N317V
Auf jeden Fall schon mal Danke Euch beiden für die superschnelle Hilfe. Hat noch jemand ne Erklärung dafür, warum self nicht definiert ist? Ist doch auch der erste Parameter.

Verfasst: Dienstag 23. August 2005, 18:45
von henning
Ich nehme mal an, dass die Parameter erst im Funktionsrumpf als definiert gelten, wenn die Parameterliste angearbeitet ist.
Die default-Parameter-Zuweisung ist ja aber innerhalb der Parameterliste, deshalb ist self zu dem Zeitpunkt noch nicht definiert.

Das muss auch so sein, denn wenn ich folgendes habe:

Code: Alles auswählen

def foo(a, b, c=a.lower()):
  print a, b, c

d = {
 "a": "HALLO",
 "b": "blah",
 "c": 34
}
foo(**d)
dann kann dies nicht funktionieren, da ja nicht klar ist, in welcher Reihenfolge die keyowrd-werte aus dem dictionary geholt werden! (Elemente in einem Dictonary haben keine vorhersagbare Reihenfolge, zumindest konzeptionell)

PS: Man könnte eventuell einwenden, dass die keywords in Reihenfolge der Parameterliste raus geholt werden.
Fällt mir auch kein gutes Gegenargument zu ein, aber vielleicht veranschaulicht es das Dilemma trotzdem ein wenig.

Verfasst: Dienstag 23. August 2005, 22:08
von BlackJack
mawe hat geschrieben:Hi!

Deine Methode etwas abgewandelt:

Code: Alles auswählen

In [1]: class Foo:
   ...:     def __init__(self):
   ...:         self.var = "blabla"
   ...:     def methode(self, parameter=None):
   ...:         bla = parameter or self.var
   ...:         print bla
Ich würde nach Möglichkeit immer mit ``if`` auf ``is not None`` prüfen wenn man sich nicht ganz sicher ist, das nie ein Wert übergeben werden können soll, der "falsch" ist. Da oben kann man `parameter` zum Beispiel nicht explizit auf eine leere Zeichenkette setzen. Oder bei numerischen Werten schliesst man die 0 aus usw.

Verfasst: Mittwoch 24. August 2005, 06:47
von jens
Ich würde es auf lieber mit if machen, weil's einfacher zu verstehen ist... Die or Variante ist mir zu abgefahren, auch wenns schön klein ist ;)

Verfasst: Mittwoch 24. August 2005, 09:15
von N317V
Ich find die or-Variante voll geil; sehr pythonic :) Und ich bin mir auch ganz sicher, dass da kein Wert übergeben werden soll, der False ergibt.

@henning: Dein Code-Beispiel leuchtet mir ein. Warum aber self an jede Methode der Klasse übergeben werden muss, andererseits aber zu dem Zeitpunkt nicht definiert ist, ist mir schleierhaft. Zumal ich diese Art der Vorbelegung für am sinnvollsten halte.

Verfasst: Mittwoch 24. August 2005, 09:52
von Gast
Das mit dem self ist eigentlich ganz logisch, wenn man mal
kurz vergisst, dass die Funktionen zu einem Objekt gehören.

An und für sich sind Funktionen, die in einer Klasse definiert werden
ja erstmal Klassenvariablen die zufällig den Typ Funktion haben.
Die gibts aber nur einmal pro Klasse, daher wissen sie nichts von einer Instanz (also dem Objekt der Klasse)!

Deswegen muss man self als Parameter entgegennehmen, damit man Zugriff auf das Objekt hat.

Wenn man folgendes hat:

Code: Alles auswählen

class Klasse:
  def func(self, a, b):
     self.blah = "foo"

k = Klasse()

Dann ist

Code: Alles auswählen

k.func(3, 4)
Nur eine andere Schreibweise
(also wenn an so will "sntactic sugar") für

Code: Alles auswählen

Klasse.func(k, 3, 4)

Verfasst: Mittwoch 24. August 2005, 09:54
von henning
Das letzte Posting ist von mir, war nicht eingeloggt.

Verfasst: Mittwoch 24. August 2005, 10:04
von N317V
@henning:

Heißt das, ich rufe eigentlich die Klasse auf, "starte" eine Funktion und übergebe ihr die Instanz und weitere Parameter? Puh! Ganz schön wirr.

Aber selbst wenn: wieso kann ich die Instanz übergeben, eine der Instanz bei deren Erzeugung zugewiesenes Attribut jedoch nicht. Das macht doch keinen Sinn.

Verfasst: Mittwoch 24. August 2005, 10:06
von jens
Anonymous hat geschrieben:Nur eine andere Schreibweise
(also wenn an so will "sntactic sugar") für

Code: Alles auswählen

Klasse.func(k, 3, 4)
Das geht so allerdings nicht! So funktionierts:

Code: Alles auswählen

Klasse().func(k, 3, 4)

Verfasst: Mittwoch 24. August 2005, 10:18
von henning
Also ich hatte mein Beispiel nicht getestet, aber was du schreibst wundert mich, weil Klasse() doch auch wieder ein Objekt ist, da müssten der Funktion insgesamt 4 Parameter übergeben werden, oder?!

N317V:
Nein, eigentlich ganz logisch, man ists nur nicht geöhnt von anderen OO-Sprachen ,-)

Ausserdem kannst du auch ein attribut der instanz übergeben:

Code: Alles auswählen

class Klasse:
  def __init__(self):
     self.x = 45
     self.y = 36
  def func(self, a, b):
     return self.y + a + b;

k = Klasse()
k.func(k.x, 7)
self ist bloß innerhalb der Parameterliste der Funktion nicht definiert!

Verfasst: Mittwoch 24. August 2005, 10:32
von mawe
henning hat geschrieben: aber was du schreibst wundert mich, weil Klasse() doch auch wieder ein Objekt ist, da müssten der Funktion insgesamt 4 Parameter übergeben werden, oder?!
Richtig, wie man auch an der Fehlermeldung sieht die man erhält :)
Klasse.func(k, 3, 4) stimmt schon.

Verfasst: Mittwoch 24. August 2005, 10:37
von jens
Halt. In eurem Fall wird bei k.func(k.x, 7) die Klassenvariable 'x' mitgeschickt. Das geht natürlich nicht, wenn es k nicht gibt ;)

Schauen wir uns mal folgende Klasse an:

Code: Alles auswählen

class foo:
    irgendwas = 'dingsbums'

    def methodeEins(self, parameter=irgendwas):
        print parameter
Hierbei geht der "direkte" Aufruf schon so: foo().methodeEins("jo") aber nicht so: foo.methodeEins("jo")

Verfasst: Mittwoch 24. August 2005, 10:44
von mawe
jens, bitte lies Dir noch mal den Beitrag von henning und Deine Antwort darauf durch. Dort ist nämlich mit k = Klasse() längst eine Instanz erzeugt ;)

Verfasst: Mittwoch 24. August 2005, 10:46
von jens
Ups :oops: Jetzt verstehe ich erst wie das gemeint war :lol: