Piszę aplikację w języku Python, która przyjmuje jako polecenie argument, na przykład:
$ python myapp.py command1
Chcę, aby aplikacja była rozszerzalna, to znaczy mogła dodawać nowe moduły, które implementują nowe polecenia bez konieczności zmiany głównego źródła aplikacji. Drzewo wygląda mniej więcej tak:
myapp/
__init__.py
commands/
__init__.py
command1.py
command2.py
foo.py
bar.py
Chcę więc, aby aplikacja znalazła dostępne moduły poleceń w czasie wykonywania i uruchomiła odpowiedni.
Python definiuje funkcję __import__ , która pobiera ciąg nazwy modułu:
__import __ (name, globals = None, locals = None, fromlist = (), level = 0)
Funkcja importuje nazwę modułu, potencjalnie używając danych globalnych i lokalnych do określenia, jak interpretować nazwę w kontekście pakietu. Fromlist podaje nazwy obiektów lub podmodułów, które powinny zostać zaimportowane z modułu podanego przez name.
Źródło: https://docs.python.org/3/library/functions.html# import
Więc obecnie mam coś takiego:
command = sys.argv[1]
try:
command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
# Display error message
command_module.run()
Działa to dobrze, zastanawiam się tylko, czy jest jakiś bardziej idiomatyczny sposób na osiągnięcie tego, co robimy z tym kodem.
Zauważ, że szczególnie nie chcę wchodzić w użycie jaj lub punktów rozszerzenia. To nie jest projekt typu open source i nie oczekuję, że pojawią się „wtyczki”. Chodzi o to, aby uprościć główny kod aplikacji i wyeliminować potrzebę jego modyfikacji za każdym razem, gdy dodawany jest nowy moduł poleceń.
dir(__import__)
. Lista from powinna być listą nazw do emulacji „z importu nazw ...”.
importlib
: stackoverflow.com/a/54956419/687896