Zanurkuj w Pythonie/Korzystanie z sys.modules

Korzystanie z sys.modules

edytuj

Moduły, podobnie jak wszystko inne w Pythonie, są obiektami. Jeśli wcześniej zaimportowaliśmy pewien moduł, możemy pobrać do niego referencję za pośrednictwem globalnego słownika sys.modules.

Przykład. Wprowadzenie do sys.modules
>>> import sys                          #(1)
>>> print '\n'.join(sys.modules.keys()) #(2)
win32api
os.path
os
exceptions
__main__
ntpath
nt
sys
__builtin__
site
signal
UserDict
stat
  1. Moduł sys zawiera informacje dotyczące systemu jak np. wersję uruchomionego Pythona (sys.version lub sys.version_info) i opcje dotyczące systemu np. maksymalna dozwolona głębokość rekurencji (sys.getrecursionlimit() i sys.setrecursionlimit()).
  2. sys.modules jest słownikiem zawierającym wszystkie moduły, które zostały zaimportowane od czasu startu Pythona. W słowniku tym kluczem jest nazwa danego modułu, a wartością jest obiekt tego modułu. Dodajmy, że jest tu więcej modułów niż nasz program zaimportował. Python wczytuje niektóre moduły podczas startu, a jeśli używasz IDE Pythona , sys.modules zawiera wszystkie moduły zaimportowane przez wszystkie programy uruchomione wewnątrz IDE.

Poniższy przykład pokazuje, jak wykorzystywać sys.modules.

Przykład. Korzystanie z sys.modules
>>> import fileinfo                    #(1)
>>> print '\n'.join(sys.modules.keys())
win32api
os.path
os
fileinfo
exceptions
__main__
ntpath
nt
sys
__builtin__
site
signal
UserDict
stat
>>> fileinfo
<module 'fileinfo' from 'fileinfo.pyc'>
>>> sys.modules["fileinfo"]            #(2)
<module 'fileinfo' from 'fileinfo.pyc'>
  1. Podczas importowania nowych modułów, zostają one dodane do sys.modules. To tłumaczy dlaczego ponowne zaimportowanie tego samego modułu jest bardzo szybkie. Otóż Python aktualnie posiada wczytany i zapamiętany moduł w sys.modules, więc za drugim razem kiedy importujemy moduł, Python spogląda po prostu tylko do tego słownika.
  2. Podając nazwę wcześniej zaimportowanego modułu (w postaci łańcucha znaków), możemy pobrać referencję do samego modułu poprzez bezpośrednie wykorzystanie słownika sys.modules.

Kolejny przykład pokazuje, jak wykorzystywać atrybut klasy __module__ razem ze słownikiem sys.modules, aby pobrać referencję do modułu, w którym ta klasa jest zdefiniowana.

Przykład. Atrybut klasy __module__
>>> from fileinfo import MP3FileInfo
>>> MP3FileInfo.__module__               #(1)
'fileinfo'
>>> sys.modules[MP3FileInfo.__module__]  #(2)
<module 'fileinfo' from 'fileinfo.pyc'>
  1. Każda klasa Pythona posiada wbudowany atrybut klasy, jakim jest __module__, a który przechowuje nazwę modułu, w którym dana klasa jest zdefiniowana.
  2. Łącząc to z sys.modules, możemy pobrać referencję do modułu, w którym ta klasa jest zdefiniowana.

Teraz już jesteś przygotowany do tego, aby zobaczyć w jaki sposób sys.modules jest wykorzystywany w fileinfo.py, czyli przykładowym programie wykorzystanym w rozdziale 5. Poniższy przykład przedstawia fragment kodu.

Przykład. sys.modules w fileinfo.py
    def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):         #(1)
        u"zwraca klasę metadanych pliku na podstawie podanego rozszerzenia"                       
        subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]          #(2)
        return hasattr(module, subclass) and getattr(module, subclass) or FileInfo   #(3)
  1. Jest to funkcja z dwoma argumentami. Argument filename jest wymagany, ale module jest argumentem opcjonalnym i domyślnie wskazuje na moduł, który zawiera klasę FileInfo. Wygląda to nieefektywnie, ponieważ może się wydawać, że Python wykonuje wyrażenie sys.modules za każdym razem, gdy funkcja zostaje wywołana. Tak naprawdę, Python wykonuje domyślne wyrażenia tylko raz, podczas pierwszego zaimportowania modułu. Jak zobaczymy później, nigdy nie wywołamy tej funkcji z argumentem module, więc argument module służy nam raczej jako stała na poziomie tej funkcji.
  2. Funkcji tej przyjrzymy się później, po tym, jak zanurkujemy w module os. Na razie zaufaj, że linia ta sprawia, że subclass przechowuje nazwę klasy np. MP3FileInfo.
  3. Już wiemy, że funkcja getattr zwraca nam referencje do obiektu poprzez nazwę. hasattr jest funkcją uzupełniającą, która sprawdza, czy obiekt posiada określony atrybut. W tym przypadku sprawdzamy, czy moduł posiada określoną klasę (funkcja ta działa na dowolnym obiekcie i dowolnym atrybucie, podobnie jak getattr). Ten kod możemy na język polski przetłumaczyć w ten sposób: „Jeśli ten moduł posiada klasę o nazwie zawartej w zmiennej subclass, to ją zwróć, w przeciwnym wypadku zwróć klasę FileInfo”.

Materiały dodatkowe

edytuj