Zanurkuj w Pythonie/Dynamiczne importowanie modułów
Dynamiczne importowanie modułów
[edytuj]OK, dość filozofowania. Pogadajmy o dynamicznym importowaniu modułów.
Najpierw zerknijmy jak normalnie importuje się moduły. Składnia polecenia import module sprawdza ścieżkę w poszukiwaniu nazwanego modułu i importuje go po nazwie. W ten sposób można importować kilka modułów na raz, podając nazwy modułów oddzielone przecinkiem. Zresztą, robiliśmy już to w pierwszej linii skryptu z tego rozdziału.
Przykład 16.13. Importowanie wielu modułów na raz
import sys, os, re, unittest #(1)
- Importowane są cztery moduły na raz: sys (funkcje systemowe oraz dostępu do parametrów przekazywanych z linii poleceń), os (wykonywanie funkcji systemowych takich jak np. listowanie katalogów), re (wyrażenia regularne), oraz unittest (testy jednostkowe).
A teraz zróbmy to samo, jednak przy użyciu dynamicznego importowania.
Przykład 16.14. Dynamiczne importowanie modułów
>>> sys = __import__('sys') #(1) >>> os = __import__('os') >>> re = __import__('re') >>> unittest = __import__('unittest') >>> sys #(2) >>> <module 'sys' (built-in)> >>> os >>> <module 'os' from '/usr/local/lib/python2.2/os.pyc'>
- Wbudowana funkcja __import__ robi to samo co użycie polecenia import, jednak jest to funkcja rzeczywista, która przyjmuje ciąg znaków jako argument.
- Zmienna sys staje się modułem sys, to tak jakby napisać import sys. Zmienna os staje się modułem os i tak dalej.
Reasumując, __import__ importuje moduł, jednak aby tego dokonać, pobiera jako argument ciąg znaków. W tym przypadku moduł, który zaimportowaliśmy był po prostu na sztywno zakodowanym ciągiem znaków, jednak nic nie stało na przeszkodzie, aby była to zmienna lub wynik działania funkcji. Zmienna, pod którą podstawiamy moduł, nie musi się nazywać tak samo jak nazwa modułu, który importujemy. Równie dobrze moglibyśmy zaimportować szereg modułów i przypisać je do listy.
Przykład 16.15. Dynamiczne importowanie listy modułów
>>> moduleNames = ['sys', 'os', 're', 'unittest'] #(1) >>> moduleNames ['sys', 'os', 're', 'unittest'] >>> modules = map(__import__, moduleNames) #(2) >>> modules #(3) [<module 'sys' (built-in)>, <module 'os' from 'c:\Python22\lib\os.pyc'>, <module 're' from 'c:\Python22\lib\re.pyc'>, <module 'unittest' from 'c:\Python22\lib\unittest.pyc'>] >>> modules[0].version #(4) '2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)]' >>> import sys >>> sys.version '2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)]'
- moduleNames jest po prostu listą ciągów znaków. Nic nadzwyczajnego, za wyjątkiem tego, że akurat te ciągi znaków są nazwami modułów, które moglibyśmy zaimportować, jeśli byśmy chcieli.
- Wyobraźmy sobie, że chcieliśmy je zaimportować, a dokonaliśmy tego poprzez mapowanie funkcji __import__ na listę. Pamiętajmy jednak, że każdy element listy (moduleNames) będzie przekazany jako argument do wywołania raz za razem funkcji (__import__), dzięki czemu zostanie zbudowana i zwrócona lista wartości wynikowych
- Tak więc z listy ciągów znaków stworzyliśmy tak na prawdę listę rzeczywistych modułów. (Nasze ścieżki mogą się różnić w zależności od systemu operacyjnego, na którym zainstalowaliśmy Pythona, faz księżyca i innych takich tam.)
- Aby upewnić się, że są to tak na prawdę moduły, zerknijmy na niektóre ich atrybuty. Pamiętajmy, że modules[0] jest modułem sys, więc modules[0].version odpowiada sys.version. Wszystkie pozostałe atrybuty i metody tych modułów są także dostępne. Nie ma nic niezwykłego w poleceniu import, tak samo jak nie ma nic magicznego w modułach. Moduły są obiektami. Wszystko jest obiektem.
Teraz już powinniśmy móc wszystko to poskładać do kupy i rozszyfrować, o co tak na prawdę chodzi w kodzie zamieszczonych tutaj przykładów.