Methodenargument mit Instanzwert per default belegen...

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
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

ich kann einfach nicht verstehen, weshalb folgendes nicht funktioniert:

Code: Alles auswählen

class Test():
    def __init__(self):
        self.instance_attribut = 'Wo bin ich?'

    def zeig_dich(self, argument=self.instance_attribut):
        pass
Obiges Beispiel erzeugt einen NameError.

Es ist doch so, dass beim Aufruf (wobei es soweit ja gar nicht kommt, weil NameError) eines Instanzattributes zuerst geschaut wird, ob es sich um ein Datenobjekt handelt. Wenn das nicht der Fall ist, wird geprüft, ob es unter dem Namen des Attributes eine Funktion innerhalb der Klasse gibt. Ist das der Fall, wird die Instanz zusammen mit der Funktion zu einer Methode zusammengepackt. Wenn dem so ist: Weshalb ist dann ein Instanzattribut als Methodenargument nicht möglich? Nach Erzeugen der Methode ist das Instanzattribut doch auch vorhanden!

Bitte, lasst mich an Eurer grenzenlosen Weisheit teilhaben!! :?

Gruß
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
lunar

Standardparameter werden nicht erst beim Aufruf, sondern schon bei der Auswertung der Methodendefinition ausgewertet. Methodendefinitionen wiederum werden ausgewertet, wenn die Klassendefinition ausgewertet wird. Zu diesem Zeitpunkt kann noch gar kein Exemplar existieren, weil die Klasse selbst noch nicht vollständig ist. Deshalb gibt es kein "self" und somit auch eine Exemplarattribute.

Die Lösung ist einfach:

Code: Alles auswählen

class Foo:
    def __init__(self):
        self.foo = 'foo'
    
    def some_method(self, param=None):
        if param is None:
            param = self.foo
Das kannst Du auch selbst prüfen. Schau Dir einfach mal die Ausgabe von folgendem Quelltext an:

Code: Alles auswählen

def foo():
    print('calling foo')
    return 'foo'

class Foo:
    print('evaluating class definition')

    def __init__(self):
        print('creating instance')
        self.param = 'bar'

    print('evaluating method definition')
    def some_method(self, param=foo()):
        print('calling some_method({0})'.format(param))
    print('method definition done')

    print('class definition done')

f = Foo()
f.some_method()
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Danke für Deine Erläuterung...
lunar hat geschrieben:Die Lösung ist einfach...
So ähnlich hab' ich das bisher auch gelöst. Gefällt mir halt nicht so gut, wenn ich auf der einen Seite die Möglichkeit habe, Argumente per default zu belegen, im Falle von Instanzattributen als Defaultwert aber dann doch eine Prüfung einbauen muss.
Auch wenn mir Deine Erklärung einleuchtet. Schön find' ich es nicht. :)

Gruß
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Klassenattribute sind IIRC fuer die Methodendefinition verfuegbar, wenn es sich also um "Konstanten" handelt, liesse sich das damit erledigen.

Btw wenn die Instanzattribute nicht konstant sind, wuerdest du mit dem naiven Ansatz gegen die Wand laufen, da die Default-Argumente nur einmal ausgewertet werden.
Antworten