2012-11-02 3 views
5

Mam następujące hierarchii projektu:Importowanie biblioteki klas w Pythonie

project_dir 
    lib 
    __init__.py 
    ... 
    some_script.py 
    ... 
    agent 
     __init__.py 
     ... 
     errors.py 
     some_agent_script.py 
     ... 

Istnieje definicja klasy SomeException w lib/agent/erros.py używam następujący kod, aby zaimportować je wewnątrz lib/agent/some_agent_script. py:

from errors import SomeException 

również stosowanie zgodnie kod importowania lib/some_script.py

from agent.errors import SomeException 

Problemem jest, gdy podnoszą SomeException lib/czynnik/some_agent_script.py następnie lib/some_script.py nie może złapać ją w bloku z wyjątkiem:

try: 
    # Here comes a call to lib/agent/some_agent_script.py function 
    # that raises SomeException 
except SomeException, exc: 
    # Never goes here 
    print(exc) 
except Exception, exc: 
    print(exc.__class__.__name__) # prints "SomeException" 

    # Let's print id's 
    print(id(exc.__class__)) 
    print(id(SomeException)) 
    # They are different! 

    # Let's print modules list 
    pprint.pprint(sys.modules) 

można zobaczyć w sys.modules że moduł erros importowano dwukrotnie: pierwszy z „agent.errors” klucz, a drugi z kluczem

Poniższy kod „lib.agent.errors” idzie dobrze, ale to nie jest piękne rozwiązanie:

agent_errors = sys.modules.get('agent.errors') 
from agent_errors import SomeException 

try: 
    # Here comes a call to lib/agent/some_agent_script.py function 
except SomeException: 
    print('OK') 

Co należy zrobić, aby moduł nie był importowany dwukrotnie?

+0

Jaka jest wersja Pythona? –

+0

Python 2.6.6 – fey

+2

Powiązane uwagi: [Pytanie SO] (http://stackoverflow.com/questions/1459236/module-reimported-if-imported-from-different-path), [PEP 395] (http://www.python.org/dev/peps/pep-0395/) –

Odpowiedz

2

Powinieneś zawsze używać w pełni kwalifikowanego importu.

from lib.agent.errors import SomeException 

Zrób to w każdym module, który z niego korzysta. Wtedy zawsze będzie mieć tę samą nazwę pakietu. Prawdopodobnie powinieneś również zmienić nazwę pakietu najwyższego poziomu. Nazwa "lib" jest zbyt ogólna.

To również pozwoli Ci zaoszczędzić sobie trochę bólu głowy, jeśli wymienisz moduł tak samo jak podstawa lub moduł "zapas". Załóżmy na przykład, że utworzyłeś moduł lib/agent/socket.py i , który napisałeś: import socket. Nie dostaniesz swojego modułu, ale zapasowy.

Więc lepiej jest mieć zwyczaj używania zawsze pełnych nazw paczek, od zwykłego korzenia, jeśli możesz.

Alternatywą jest użycie importu bezwzględnego.

from __future__ import absolute_import 

import .errors 

Zwróć uwagę na kropkę wiodącą. To wyraźnie importuje z bieżącego pakietu. Powinien również rozwiązać twój problem, ale przyznaję, że go nie wypróbowałem.

+0

Brzmi nieźle, ale lib/agent jest biblioteką, która jest używana w kilku projektach. Nie jest dobrze określać tam w pełni kwalifikowaną nazwę, ponieważ w innych projektach agent może znajdować się nie w module lib. – fey

+0

@fey Zaktualizowałem swoją odpowiedź za pomocą alternatywnej metody. – Keith

+0

Dzięki! Właśnie tego potrzebowałem! Jest jeszcze jedno: w obu modułach trzeba użyć absolute_import, który podnosi i obsługuje wyjątek. – fey