La situazione è la seguente: si dispone di uno script (run.py
), un pacchetto test
e il suo sottomodulo test.b
.
Ogni volta che si importa un sottomodulo in Python, il nome del sottomodulo viene automaticamente memorizzato nel pacchetto genitore. In questo modo, quando si esegue import collections.abc
(o from collections.abc import Iterable
o simile), il pacchetto collections
ottiene automaticamente l'attributo abc
.
Questo è ciò che sta accadendo qui. Quando si esegue:
from b import B
il nome b
viene automaticamente caricata test
, perché b
è un modulo del pacchetto test
.
Anche se non si fa esplicitamente , ogni volta che si importa quel modulo, il nome viene inserito in test
. Perché b
è un sottomodulo di test
e appartiene a test
.
nodo laterale: il codice non funziona con Python 3, perché relative imports have been removed.Per rendere il vostro lavoro con il codice Python 3, si dovrebbe scrivere:
from test.b import B
Questa sintassi è perfettamente identica a from b import B
, ma è molto più esplicito, e dovrebbe aiutare a capire cosa sta succedendo.
Riferimento: il Python reference documentation spiega anche questo comportamento, e include un esempio disponibile, molto simile a questa situazione (la differenza è solo che un'importazione assoluto viene utilizzato, al posto di un import relativa).
Quando un modulo viene caricato utilizzando qualsiasi meccanismo (per esempio importlib
API, i import
o import-from
dichiarazioni, o incorporato __import__()
) un legante è collocato nel namespace del modulo padre all'oggetto modulo. Ad esempio, se il pacchetto spam
ha un sottomodulo foo
, dopo l'importazione di spam.foo
, spam
avrà un attributo foo
associato al sottomodulo.
Diciamo che si ha la seguente struttura di directory:
spam/
__init__.py
foo.py
bar.py
e spam/__init__.py
ha le seguenti linee in esso:
from .foo import Foo
from .bar import Bar
quindi eseguire il seguente mette un nome vincolante per foo
e bar
nel spam
modulo:
>>> import spam
>>> spam.foo
<module 'spam.foo' from '/tmp/imports/spam/foo.py'>
>>> spam.bar
<module 'spam.bar' from '/tmp/imports/spam/bar.py'>
Date le regole di binding del nome familiare di Python, questo potrebbe sembrare sorprendente, ma in realtà è una caratteristica fondamentale del sistema di importazione. Il mantenimento invariante è che se hai sys.modules['spam']
e sys.modules['spam.foo']
(come faresti dopo l'importazione di cui sopra), quest'ultimo deve apparire come l'attributo foo
del primo.
scuse per la risposta sbagliata ... appena rimosso per non creare confusione. @ Poke grazie per indicarlo ... non ho notato inizialmente quello che hai citato. –