Wie getattr() auf selbem Modul aufrufen als Dispatcher?

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
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hallo zusammen,

ich habe grad mal überlegt, dass bei vielen kleineren Scripten ein harmloser Dispatcher ja nicht immer über ein Dict aufgebaut werden müßte, so wie hier:

Code: Alles auswählen

def foo(): pass
def bar(): pass

dispatch = {"foo": foo, "bar": bar}
dispatch[sys.argv[1]]()
Sofern man die Namen als String 1:1 auf die Namen im Modul mappt, könnte man sich das Dict ja auch sparen. Mir fiel da spontan getattr() ein, allerdings benötigt das ja als ersten Parameter ein Objekt. Meine Frage ist also, ob / wie man an das Objekt des Moduls zugreifen kann?

Code: Alles auswählen

def foo(): pass
def bar(): pass

getattr(???, sys.argv[1])()
Oder kann man darauf gar nicht zugreifen? Gibt es dann ggf. eine Alternative, um von einem String auf ein Funktionsobjekt zu schließen?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Du kannst __main__ explizit importieren und dann auf dessen Attribute zugreifen. Ich weiß aber nicht, ob es das ist, was du vorhast. Habe deinen Plan ehrlich gesagt nicht wirklich verstanden.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Ah, jetzt verstehe ich! Also ich würde wie gesagte __main__ importieren und das inspect-Modul nutzen, um Funktionen herauszufiltern.

Code: Alles auswählen

>>> import __main__                                                                               
>>> import inspect                                                                                
>>> inspect.getmembers(__main__, inspect.isfunction)                                              
[]                                                                                                
>>> def foo(a=42): pass                                                                           
...                                                                                               
>>> def bar():                                                                                    
...     print 23                                                                                  
...                                                                                               
>>> inspect.getmembers(__main__, inspect.isfunction)                                              
[('bar', <function bar at 0x15355f0>), ('foo', <function foo at 0x13a2930>)]
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ah... danke!

Wobei ich inspect jetzt eher umständlich finde. Es soll ja grad schön kurz und kompakt sein.

So find ich es ganz hübsch:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import __main__

def foo():
    return "foo"

def bar():
    return "bar"

def usage():
    return "Usage:\n\t./script.py foo|bar"

if __name__ == "__main__":
    print getattr(__main__, sys.argv[1], usage)()
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Oder noch einfacher:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

def foo():
    return "foo"

def bar():
    return "bar"

def usage():
    return "Usage:\n\t./script.py foo|bar"

if __name__ == "__main__":
    print globals().get(sys.argv[1], usage)()
Bottle: Micro Web Framework + Development Blog
silver0346
User
Beiträge: 5
Registriert: Freitag 13. Juni 2014, 21:52

Hallo zusammen,

ich stehe vor der gleichen Aufgabe wie Hyperion: In Abhängigkeit von gegebenen Strings sollen Funktionen aufgerufen werden. Bisher hatte ich diese Funktionen in eine eigene Klasse ausgelagert. Da funktioniert getattr() zufriedenstellend. Wenn ich diese Funktion in die eigentliche Klasse verschiebe findet getattr() sich nicht zurecht.

Mein Testcode:

Code: Alles auswählen

import __main__

class TestGetattr(object):
    def __init__(self):
        super(TestGetattr, self).__init__()

    def get_1(self):
        print('get_1')

    def get_2(self):
        print('get_2')

    def main(self):
        calls = [1, 2]
        for _item in calls:
            print(_item)
            _fkt = 'get_' + str(_item)
            _call = getattr(__main__, _fkt)
            _call()

if __name__ == '__main__':
    m = TestGetattr()
    m.main()
Ergebnis ist:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:/workspace/python/fill/test_getattr.py", line 23, in <module>
    m.main()
  File "C:/workspace/python/fill/test_getattr.py", line 18, in main
    _call = getattr(__main__, _fkt)
AttributeError: 'module' object has no attribute 'get_1'
1
An welcher Stelle liegt denn mein Denkfehler?

Vielen Dank im Voraus.
BlackJack

@silver0346: Zähl doch mal die Attribute auf die das *Modul* hat. Glaubst Du tatsächlich das *Modul* hat ein `get_1`-Attribut?

Edit: Deine Vermutung(en) kannst Du mit der `dir()`-Funktion auch gleich gegenprüfen.
silver0346
User
Beiträge: 5
Registriert: Freitag 13. Juni 2014, 21:52

Sorry,

ich hab noch etwas weiter rumprobiert. self hat get_x. :oops:

Vielen Dank. Paßt in die Geschichte mit dem offenen Brief aus http://www.python-forum.de/viewtopic.php?f=1&t=23839
Antworten