Attribut als default-Parameter in Klassenmethode?

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
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

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
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Vielleicht nicht ganz was du willst:

Code: Alles auswählen

class foo:
    irgendwas = 'dingsbums'

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

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

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.
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

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.
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

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.
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.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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 ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

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.
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
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)
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Das letzte Posting ist von mir, war nicht eingeloggt.
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

@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.
Zuletzt geändert von N317V am Mittwoch 24. August 2005, 10:42, insgesamt 1-mal geändert.
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

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!
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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")

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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 ;)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ups :oops: Jetzt verstehe ich erst wie das gemeint war :lol:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten