Seite 1 von 1

identifizieren der Argument-Namen einer Methode...

Verfasst: Donnerstag 29. September 2005, 19:14
von jens
Mit getattr kann ich ja die methode einer Klasse bekommen... Kann man auch rausbekommen, welche Argumente die Klasse erwartet???
Bsp.:

Code: Alles auswählen

class test:
  def test1(self, arg1, arg2):
    print arg1, arg2
Wie bekomme ich raus, das test().test1 die Argumente arg1 und arg2 erwartet? Ich brauche die Namen als Strings...

Verfasst: Donnerstag 29. September 2005, 21:37
von BlackJack
Das könnte so gehen:

Code: Alles auswählen

In [22]: class test:
   .22.:    def test1(self, arg1, arg2):
   .22.:      print arg1, arg2
   .22.:

In [23]: inspect.getargs(test.test1.im_func.func_code)
Out[23]: (['self', 'arg1', 'arg2'], None, None)
Ich gehe mal davon aus, das das recht CPython-spezifisch ist. Wozu brauchst Du die Namen denn?

Verfasst: Freitag 30. September 2005, 09:22
von jens
Ich wollte das im PyLucid ModulManager einbauen... Allerdings mach ich das am besten einfach mit try und übergebe die Daten auf gut glück ;)
Mal sehen...

Verfasst: Freitag 30. September 2005, 10:45
von henning
An sowas Ähnlichem bin ich momentan auch dran (siehe aktueller Thread), inspect macht nichts anderes als ein paar Werte einer Funktion auszulesen:

Code: Alles auswählen

>>> class Foo:
...   def my_fn(self, something, irgendwas="default", foo=3.14):
...     lokal = 67
... 
>>> f = Foo()
>>> print f.my_fn.im_func.func_code.co_argcount
4
>>> print f.my_fn.im_func.func_code.co_varnames 
('self', 'something', 'irgendwas', 'foo','lokal')
>>> print f.my_fn.im_func.func_defaults
('default', 3.1400000000000001)
Also man kann schon ne ganze Menge über ne Funktion rauskriegen, ohne sie aufzurufen und sogar, ohne das inspect-Modul zu laden ,-)

Verfasst: Freitag 30. September 2005, 12:32
von jens
Zu früh gefreut, denn ".im_func.func_code.co_varnames" liefert nämlich nicht nur die argumente der Methode, sondern zusätzlich alle Variablen, die es in der Methode gibt:

Code: Alles auswählen

class test:
    def test1(self, arg1, arg2):
        ich_auch = 123
        print arg1, arg2
        und_auch_ich = "blabla"

print test().test1.im_func.func_code.co_varnames
Liefert:

Code: Alles auswählen

('self', 'arg1', 'arg2', 'ich_auch', 'und_auch_ich')
In meinem Fall brauche ich aber wirklich nur die argumente im "Methodenkopf" (also 'arg1', 'arg2') :(

Verfasst: Freitag 30. September 2005, 12:42
von Leonidas
Ich würde eher das Modul inspect verwenden, statt auf irgendwelche schlecht dokumentierten Sachen zuzugreifen - vielleicht will es noch jemand enderes lesen und bei inspect sieht man halt sofort was ich mir dabei gedacht hatte.

Verfasst: Freitag 30. September 2005, 12:50
von jens
Hast recht, was die Doku angeht. Ich hab nur das gefunden:
http://www.python.org/doc/current/ref/types.html#l2h-87

Aber ist es ein Grund die eingebaute Funktion nicht zu benutzten? Ich denke es ist ehr ein ansporn die Doku mal aufzumöbeln... Aber das ist wieder ein anderes Thema :?

Ich sehe einfach den Vorteil darin, inspect nicht importieren zu müßen :)

Verfasst: Samstag 1. Oktober 2005, 20:59
von jens
Zu früh gefreut, denn ".im_func.func_code.co_varnames" liefert nämlich nicht nur die argumente der Methode, sondern zusätzlich alle Variablen, die es in der Methode gibt:

Code: Alles auswählen

class test:
    def test1(self, arg1, arg2):
        ich_auch = 123
        print arg1, arg2
        und_auch_ich = "blabla"

print test().test1.im_func.func_code.co_varnames
Liefert:

Code: Alles auswählen

('self', 'arg1', 'arg2', 'ich_auch', 'und_auch_ich')
EDIT: Wobei .im_func.func_code.co_argcount hilft mir auch schon weiter... Ich geh nun hin und fange den TypeError ab um selber eine Fehlermeldung zu generieren, die z.B. so aussieht:
ModuleManager >get_CGI_data<-error: save_internal_page() takes exactly 5 arguments ['content', 'markup', 'name', 'description'], but 3 given from CGI data: ['content', 'markup', 'description'] Compare the html form and the module manager get_CGI_data config!

Verfasst: Sonntag 2. Oktober 2005, 11:39
von jens
Doch noch eine Lösung gefunden. Ich hoffe nur, das die argumente im Methodenkopf immer zu erst kommen:

Code: Alles auswählen

class test:
    def test1(self, arg1, arg2):
        ich_auch = 123
        print arg1, arg2
        und_auch_ich = "blabla"

argcount = test().test1.im_func.func_code.co_argcount
varnames = test().test1.im_func.func_code.co_varnames
print varnames[1:argcount]
Ausgabe:
('arg1', 'arg2')

Verfasst: Sonntag 2. Oktober 2005, 22:58
von BlackJack
Ich verstehe immer noch nicht warum Du Dich auf Deine Hoffnung verlässt statt einfach das `inspect` Modul zu benutzen. Dafür ist es schliesslich da.

Verfasst: Montag 3. Oktober 2005, 10:44
von Leonidas
BlackJack hat geschrieben:Ich verstehe immer noch nicht warum Du Dich auf Deine Hoffnung verlässt statt einfach das `inspect` Modul zu benutzen. Dafür ist es schliesslich da.
jens hat geschrieben:Ich sehe einfach den Vorteil darin, inspect nicht importieren zu müßen :)
Wobei ich zugeben muss, dass ich, genauso wie du, BlackJack, den Vorteil nicht sehe, vor allem da das Modul ja so oder so in der stdlib ist. Und es ist ja nicht so, dass ein Modul hin oder her wahnsinnige Performanceunterschiede macht.

Verfasst: Dienstag 4. Oktober 2005, 06:33
von jens
BlackJack hat geschrieben:Ich verstehe immer noch nicht warum Du Dich auf Deine Hoffnung verlässt statt einfach das `inspect` Modul zu benutzen. Dafür ist es schliesslich da.
Naja, deine Begründung 'Dafür ist es schliesslich da.' ist nicht gerade überzeugend ;)
Aber gut, mir fällt ein, das ich das ganze ja nur dann brauche, wenn ein Fehler aufgetreten ist, daher importiere ich inspect dann auch nur im Fehlerfall, somit ist meine Begründung auch wiederlegt. ;)

Aber machen wir es mal so:

Code: Alles auswählen

class test:
    def test1(self, arg1, arg2):
        ich_auch = 123
        print arg1, arg2
        und_auch_ich = "blabla"

import inspect
args = inspect.getargspec(test().test1)
print args
print args[0][1:]
(['self', 'arg1', 'arg2'], None, None, None)
['arg1', 'arg2']
Darf ich denn hier hoffen, das args[0][1:] immer richtig ist?

Verfasst: Mittwoch 5. Oktober 2005, 00:36
von BlackJack
jens hat geschrieben:
BlackJack hat geschrieben:Ich verstehe immer noch nicht warum Du Dich auf Deine Hoffnung verlässt statt einfach das `inspect` Modul zu benutzen. Dafür ist es schliesslich da.
Naja, deine Begründung 'Dafür ist es schliesslich da.' ist nicht gerade überzeugend ;)
Nicht? Du verlässt Dich also lieber auf selbstgeschriebenen Quelltext, der ziemlich tief in den "Eingeweiden" der Sprache rumwühlt, anstatt ein Modul aus der Standardbibliothek zu benutzen, welches gut getestet ist, auch in der nächsten Python Version noch funktioniert und eigentlich auch in Jython, IronPython und PyPy vorhanden sein sollte. Auch wenn dort die Interna von Funktionen und Methoden ganz anders aussehen könnten und Dein Code da auf die Nase fallen könnte!? :twisted:

Verfasst: Mittwoch 5. Oktober 2005, 06:49
von jens
Die Begründung hört sich schon viel besser an. Ich verwende auch inspect... Aber...
Ich hab mir jetzt mal inspect.getargspec() angesehen. Es benutzt auch im_func, co_argcount und co_varnames. Das ganze bietet zwar noch mehr informationen, aber die brauche ich garnicht...

Verfasst: Mittwoch 5. Oktober 2005, 23:58
von BlackJack
jens hat geschrieben:Die Begründung hört sich schon viel besser an. Ich verwende auch inspect... Aber...
Ich hab mir jetzt mal inspect.getargspec() angesehen. Es benutzt auch im_func, co_argcount und co_varnames. Das ganze bietet zwar noch mehr informationen, aber die brauche ich garnicht...
Das die Funktion in CPython `im_func` usw. benutzt ist ein Implementierungsdetail. Wenn man das in Jython benutzt, könnte ich mir zum Beispiel vorstellen, das die Java Reflection API stattdessen benutzt wird. Der Vorteil: Du brauchst Dich um solche "Kleinigkeiten" nicht kümmern.