2011-06-25 11 views
5

Potrzebuję sposobem na znalezienie zależności dla każdego z podmodułów mojego Python pakiet w czasie wykonywania więc mogę zainicjować je w odpowiedniej kolejności (patrz mój obecny [EDIT:były] rozwiązanie here , co nie działa dobrze), więc najpierw użyłem standardowego modułu Pythona modulefinder, ale było to zbyt wolne (~ 1-2 sekundy na moduł).Python analizator zależność biblioteki

Moim następnym wyborem była analiza wszystkich globałów każdego modułu i znalezienie od tych globalnych, od których podmodułów zależy każdy submoduł. (To jest moje obecne rozwiązanie EDYCJA: Mam teraz lepsze rozwiązanie - zobacz moją odpowiedź). Algorytm ten jest znacznie większy niż szybszy niż modulefinder (zajmuje < 200 ms na moduł), ale działa tylko w przypadku względnego importu, zamiast w pełni kwalifikowanego stylu importu, co jest niedopuszczalne.

Więc, co potrzebne jest albo:

  • Szybszą alternatywą modulefinder
  • Alternatywny algorytm

UWAGA: nazywam mój analizator zależnościach na początku każdy moduł, jak poniżej:

# File my_package/module3.py 

import my_package.module1 # Some misc. module 
import my_package.module2 # Some other misc. module 
import my_package.dependency_analyzer 

my_package.dependency_analyzer.gendeps() 

(Tylko na wszelki wypadek).

Dziękujemy!

EDYCJA: Mam rozwiązanie teraz - zobacz moją odpowiedź.

+0

Dlaczego tak się dzieje w czasie wykonywania? Czy te zależności zmieniają się w czasie wykonywania? –

+0

Zwykle (są pewne wyjątki), ale nie chcę dodawać dodatkowego pliku mapy zależności dla każdego z moich modułów (co brzmi tak, jak sugerujesz), więc zdecydowałem się przeanalizować zależności każdego modułu podczas uruchamiania. czas. – DangerOnTheRanger

+0

Możesz też zaimplementować swoje pakiety z pewną leniwą inicjalizacją, aby ich kolejność inicjowania nie miała znaczenia. – rafalotufo

Odpowiedz

2

Chyba mam rozwiązanie moim pytaniu :)

Oto co pójdzie do dependency_analyzer modułu rozmawialiśmy o powyżej:

import sys 
from sys import _getframe as getframe 
import atexit 

examined_modules = [] 

def gendeps(): 
    """Adds the calling module to the initialization queue.""" 
    # Get the calling module's name, and add it to the intialization queue 
    calling_module_name = getframe(1).f_globals['__name__'] 
    examined_modules.append(calling_module_name) 

def init(): 
    """Initializes all examined modules in the correct order.""" 

    for module in examined_modules: 
     module = sys.modules[module] 
     if hasattr(module, 'init'): 
      module.init() 
     if hasattr(module, 'deinit'): 
      # So modules get de-initialized in the correct order, 
      # as well 
      atexit.register(module.deinit) 

Teraz, na początku każdego modułu (po wszystkie instrukcje importu - to jest najważniejsze), jest wywołanie gendeps jest umieszczony. Ten algorytm działa, ponieważ za każdym razem, gdy moduł jest importowany, wykonywane jest wywołanie gendeps. Ponieważ jednak wszystkie instrukcje importowania są umieszczane pod numerem przed w swoim własnym module, moduły najmniej zależne są umieszczane najpierw w kolejce inicjowania, a najbardziej zależne moduły są umieszczane w kolejce inicjującej jako ostatnie. .