Importazioni relative per la miliardesima volta


717

Sono stato qui:

e molti URL che non ho copiato, alcuni su SO, altri su altri siti, quando pensavo che avrei avuto la soluzione rapidamente.

La domanda che ricorre per sempre è questa: con Windows 7, Python 2.7.3 a 32 bit, come posso risolvere questo messaggio "Tentativo di importazione relativa in non pacchetto"? Ho creato una replica esatta del pacchetto su pep-0328:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

Le importazioni sono state fatte dalla console.

Ho fatto funzioni chiamate spam e uova nei loro moduli appropriati. Naturalmente, non ha funzionato. Apparentemente la risposta è nel 4 ° URL che ho elencato, ma è tutto per me ex-alunni. C'è stata questa risposta su uno degli URL che ho visitato:

Le importazioni relative utilizzano l'attributo name di un modulo per determinare la posizione di quel modulo nella gerarchia dei pacchetti. Se il nome del modulo non contiene alcuna informazione sul pacchetto (ad esempio, è impostato su "principale"), le importazioni relative vengono risolte come se il modulo fosse un modulo di livello superiore, indipendentemente da dove si trova effettivamente il modulo sul file system.

La risposta sopra sembra promettente, ma per me sono tutti i geroglifici. Quindi la mia domanda, come posso fare in modo che Python non mi ritorni "Tentativo di importazione relativa in un pacchetto"? ha una risposta che coinvolge -m, presumibilmente.

Qualcuno può dirmi perché Python dà quel messaggio di errore, cosa significa "non-pacchetto", perché e come si definisce un "pacchetto" e la risposta precisa in termini abbastanza facili da capire per un asilo .


5
Come stai tentando di utilizzare i file che mostri? Qual è il codice che stai eseguendo?
BrenBarn

Vedi python.org/dev/peps/pep-0328 . Ho usato il formato del pacchetto che ho descritto nel mio post. I file init .py sono vuoti. moduleY.py ha def spam(): pass, moduleA.py ha def eggs(): pass. Ho provato a eseguire un paio di comandi "from .something import qualcosa", ma non hanno funzionato. Ancora una volta, vedi pep-0328.

6
Vedi la mia risposta Non hai ancora chiarito completamente cosa stai facendo, ma se stai provando a fare from .something import somethingnell'interprete interattivo, ciò non funzionerà. Le importazioni relative possono essere utilizzate solo all'interno dei moduli, non in modo interattivo.
BrenBarn

105
Il semplice fatto che "miliardi" di persone - ok 83.136 a partire da questo commento - stiano avendo abbastanza difficoltà con le importazioni per cercare questa domanda; possiamo solo concludere che le importazioni di Python sono controintuitive per molti, se non per la maggior parte dei programmatori. Guido, forse dovresti accettarlo e chiedere a un comitato di riprogettare il meccanismo di importazione. Come minimo, questa sintassi dovrebbe funzionare se x.py e z.py si trovano nella stessa directory. Vale a dire se x.py ha la frase "from .z import MyZebraClass" x dovrebbe importare z ANCHE se viene eseguito come main ! Perché è così difficile?
Steve L,

4
Dopo aver letto gran parte di questo thread, sebbene non sia una risposta alla domanda, "usa solo le importazioni assolute" sembra essere la soluzione ...
CodeJockey

Risposte:


1043

Script vs. Modulo

Ecco una spiegazione La versione breve è che c'è una grande differenza tra l'esecuzione diretta di un file Python e l'importazione di quel file da qualche altra parte. Il solo fatto di sapere in quale directory si trova un file non determina in quale pacchetto Python pensa che si trovi. Ciò dipende, inoltre, da come si carica il file in Python (eseguendolo o importandolo).

Esistono due modi per caricare un file Python: come script di livello superiore o come modulo. Un file viene caricato come script di livello superiore se lo si esegue direttamente, ad esempio digitando python myfile.pysulla riga di comando. Se lo fai python -m myfile, viene caricato come modulo o se viene caricato quando importviene rilevata un'istruzione all'interno di un altro file. Può esserci solo uno script di livello superiore alla volta; lo script di livello superiore è il file Python che hai eseguito per iniziare le cose.

Naming

Quando viene caricato un file, viene assegnato un nome (che è memorizzato nel suo __name__attributo). Se è stato caricato come script di livello superiore, il suo nome è __main__. Se è stato caricato come un modulo, il suo nome è il nome del file, preceduto dai nomi di tutti i pacchetti / subpackages di cui fa parte, separati da punti.

Ad esempio, nel tuo esempio:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

se hai importato moduleX(nota: importato , non eseguito direttamente), il suo nome sarebbe package.subpackage1.moduleX. Se importato moduleA, il suo nome sarebbe package.moduleA. Tuttavia, se si esegue direttamente moduleX dalla riga di comando, il suo nome sarà invece __main__e se si esegue direttamente moduleAdalla riga di comando, il suo nome sarà __main__. Quando un modulo viene eseguito come script di livello superiore, perde il suo nome normale e il suo nome è invece __main__.

Accedere a un modulo NON tramite il suo pacchetto contenente

C'è un'ulteriore ruga: il nome del modulo dipende dal fatto che sia stato importato "direttamente" dalla directory in cui si trova o importato tramite un pacchetto. Questo fa la differenza solo se esegui Python in una directory e provi a importare un file in quella stessa directory (o in una sua sottodirectory). Ad esempio, se avvii l'interprete Python nella directory package/subpackage1e poi lo fai import moduleX, il nome moduleXsarà solo moduleXe non package.subpackage1.moduleX. Questo perché Python aggiunge la directory corrente al suo percorso di ricerca all'avvio; se trova il modulo da importare nella directory corrente, non saprà che quella directory fa parte di un pacchetto e le informazioni sul pacchetto non diventeranno parte del nome del modulo.

Un caso speciale è se si esegue l'interprete in modo interattivo (ad esempio, basta digitare pythone iniziare a immettere il codice Python al volo). In questo caso il nome di quella sessione interattiva è __main__.

Ora ecco la cosa cruciale per il tuo messaggio di errore: se il nome di un modulo non ha punti, non è considerato parte di un pacchetto . Non importa dove il file si trova effettivamente sul disco. Tutto ciò che conta è come si chiama e il suo nome dipende da come lo hai caricato.

Ora guarda la citazione che hai incluso nella tua domanda:

Le importazioni relative utilizzano l'attributo name di un modulo per determinare la posizione di quel modulo nella gerarchia dei pacchetti. Se il nome del modulo non contiene alcuna informazione sul pacchetto (ad esempio, è impostato su "principale"), le importazioni relative vengono risolte come se il modulo fosse un modulo di livello superiore, indipendentemente da dove si trova effettivamente il modulo sul file system.

Importazioni relative ...

Le importazioni relative utilizzano il nome del modulo per determinare dove si trova in un pacchetto. Quando si utilizza un'importazione relativa come from .. import foo, i punti indicano di aumentare un certo numero di livelli nella gerarchia dei pacchetti. Ad esempio, se il nome del tuo modulo attuale è package.subpackage1.moduleX, allora ..moduleAsignificherebbe package.moduleA. Per from .. importfunzionare, il nome del modulo deve avere almeno tanti punti quanti sono importnell'istruzione.

... sono relativi solo in un pacchetto

Tuttavia, se il nome del modulo è __main__, non è considerato in un pacchetto. Il suo nome non ha punti e pertanto non è possibile utilizzare from .. importistruzioni al suo interno. Se si tenta di farlo, verrà visualizzato l'errore "importazione relativa in non pacchetto".

Gli script non possono importare relativi

Quello che probabilmente hai fatto è stato provare a eseguire moduleXo simili dalla riga di comando. Quando lo hai fatto, il suo nome è stato impostato su __main__, il che significa che le importazioni relative al suo interno falliranno, perché il suo nome non rivela che si trova in un pacchetto. Si noti che ciò accadrà anche se si esegue Python dalla stessa directory in cui si trova un modulo, e quindi si tenta di importare quel modulo, perché, come descritto sopra, Python troverà il modulo nella directory corrente "troppo presto" senza accorgersene parte di un pacchetto.

Ricorda inoltre che quando esegui l'interprete interattivo, il "nome" di quella sessione interattiva è sempre __main__. Pertanto, non è possibile effettuare importazioni relative direttamente da una sessione interattiva . Le importazioni relative possono essere utilizzate solo all'interno dei file del modulo.

Due soluzioni:

  1. Se vuoi davvero eseguire moduleXdirettamente, ma vuoi comunque che sia considerato parte di un pacchetto, puoi farlo python -m package.subpackage1.moduleX. La -mdice Python per caricarlo come modulo, non come lo script di livello superiore.

  2. O forse non vuoi davvero eseguire moduleX , vuoi solo eseguire qualche altro script, diciamo myfile.py, che utilizza le funzioni all'interno moduleX. In tal caso, posizionalo myfile.py altrove , non all'interno della packagedirectory, ed eseguilo. Se dentro di myfile.pyte fai cose del genere from package.moduleA import spam, funzionerà bene.

Appunti

  • Per una di queste soluzioni, la directory del pacchetto ( packagenel tuo esempio) deve essere accessibile dal percorso di ricerca del modulo Python ( sys.path). In caso contrario, non sarà possibile utilizzare nulla nel pacchetto in modo affidabile.

  • A partire da Python 2.6, il "nome" del modulo ai fini della risoluzione del pacchetto è determinato non solo dai suoi __name__attributi ma anche dall'attributo __package__. Ecco perché sto evitando di usare il simbolo esplicito __name__per fare riferimento al "nome" del modulo. Da Python 2.6 il "nome" di un modulo è efficace __package__ + '.' + __name__, o semplicemente __name__se lo __package__è None.)


62
Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.Questo è fondamentalmente inquietante. Cosa c'è di così difficile nel guardare la directory corrente? Python dovrebbe esserne capace. È stato risolto nella versione 3x?

7
@Stopforgettingmyaccounts ...: PEP 366 mostra come funziona. All'interno di un file, puoi fare __package__ = 'package.subpackage1'o simili. Quindi solo quel file sarà sempre considerato parte di quel pacchetto anche se eseguito direttamente. Se hai altre domande su di __package__te, potresti voler fare una domanda separata, poiché stiamo risolvendo il problema della tua domanda originale qui.
BrenBarn

109
Questa dovrebbe essere la risposta a tutte le domande relative alle importazioni relative a Python. Questo dovrebbe essere nei documenti, anche.
edsioufi,

10
Vedi python.org/dev/peps/pep-0366 - "Nota che questa piastra della caldaia è sufficiente solo se il pacchetto di livello superiore è già accessibile tramite sys.path. Per l'esecuzione diretta sarebbe necessario un codice aggiuntivo che manipola sys.path funzionare senza che il pacchetto di livello superiore sia già improprio ". - questo è il bit più inquietante per me poiché questo "codice aggiuntivo" è in realtà abbastanza lungo e non può essere archiviato altrove nel pacchetto per essere eseguito facilmente.
Michael Scott Cuthbert,

14
Questa risposta è attualmente off su alcuni importanti dettagli riguardanti __name__e sys.path. In particolare, con python -m pkg.mod, __name__è impostato su __main__, no pkg.mod; le importazioni relative vengono risolte utilizzando __package__anziché __name__in questo caso. Inoltre, Python aggiunge la directory dello script anziché la directory corrente a sys.pathquando è in esecuzione python path/to/script.py; aggiunge la directory corrente a sys.pathquando si esegue la maggior parte degli altri modi, incluso python -m pkg.mod.
user2357112 supporta Monica il

42

Questo è davvero un problema in Python. L'origine della confusione è che le persone assumono erroneamente l'importazione relativa come percorso relativo che non lo è.

Ad esempio quando scrivi in faa.py :

from .. import foo

Questo ha un significato solo se faa.py è stato identificato e caricato da Python, durante l'esecuzione, come parte di un pacchetto. In tal caso, il nome del modulo per faa.py sarebbe ad esempio some_packagename.faa . Se il file fosse caricato solo perché si trova nella directory corrente, quando viene eseguito python, il suo nome non farebbe riferimento a nessun pacchetto e alla fine l'importazione relativa fallirebbe.

Una semplice soluzione per fare riferimento ai moduli nella directory corrente è quella di utilizzare questo:

if __package__ is None or __package__ == '':
    # uses current directory visibility
    import foo
else:
    # uses current package visibility
    from . import foo

6
La soluzione corretta è from __future__ import absolute_importe costringere l'utente a utilizzare correttamente il codice ... in modo che tu possa sempre farefrom . import foo
Giacomo Alzetta

@Giacomo: la risposta assolutamente giusta per il mio problema. Grazie!
Fábio,

8

Ecco una ricetta generale, modificata per adattarsi come esempio, che sto usando in questo momento per gestire le librerie Python scritte come pacchetti, che contengono file interdipendenti, dove voglio essere in grado di testarne parti frammentarie. Chiamiamo questo lib.fooe diciamo che ha bisogno di accedere a lib.fileAfunzioni f1e f2, e lib.fileBper classe Class3.

Ho incluso alcune printchiamate per illustrare come funziona. In pratica vorresti rimuoverli (e forse anche la from __future__ import print_functionlinea).

Questo esempio particolare è troppo semplice per mostrare quando è necessario inserire una voce sys.path. (Vedere la risposta di Lars' per un caso in cui ci facciamo bisogno, quando abbiamo due o più livelli di directory di pacchetto, e poi usiamo os.path.dirname(os.path.dirname(__file__))-ma in realtà non sono male neanche qui.) E 'anche abbastanza sicuro per fare questo senza il if _i in sys.pathtest. Tuttavia, se ogni file importato inserisce lo stesso percorso, ad esempio, se entrambi fileAe fileBvogliono importare utilità dal pacchetto, questo si confonde sys.pathcon lo stesso percorso molte volte, quindi è bello avere il if _i not in sys.pathnella piastra della caldaia.

from __future__ import print_function # only when showing how this works

if __package__:
    print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
    from .fileA import f1, f2
    from .fileB import Class3
else:
    print('Not a package; __name__ is {!r}'.format(__name__))
    # these next steps should be used only with care and if needed
    # (remove the sys.path manipulation for simple cases!)
    import os, sys
    _i = os.path.dirname(os.path.abspath(__file__))
    if _i not in sys.path:
        print('inserting {!r} into sys.path'.format(_i))
        sys.path.insert(0, _i)
    else:
        print('{!r} is already in sys.path'.format(_i))
    del _i # clean up global name space

    from fileA import f1, f2
    from fileB import Class3

... all the code as usual ...

if __name__ == '__main__':
    import doctest, sys
    ret = doctest.testmod()
    sys.exit(0 if ret.failed == 0 else 1)

L'idea qui è questa (e nota che tutti funzionano allo stesso modo su python2.7 e python 3.x):

  1. Se eseguito come import libo from lib import foocome un normale pacchetto di importazione dal codice ordinario, __packageè libed __name__è lib.foo. Prendiamo il primo percorso del codice, importando da .fileA, ecc.

  2. Se eseguito come python lib/foo.py, __package__sarà Nessuno e __name__lo sarà __main__.

    Prendiamo il secondo percorso del codice. La libdirectory sarà già presente, sys.pathquindi non è necessario aggiungerla. Importiamo da fileA, ecc.

  3. Se eseguito all'interno della libdirectory come python foo.py, il comportamento è lo stesso del caso 2.

  4. Se eseguito all'interno della libdirectory as python -m foo, il comportamento è simile ai casi 2 e 3. Tuttavia, il percorso della libdirectory non è presente sys.path, quindi lo aggiungiamo prima dell'importazione. Lo stesso vale se eseguiamo Python e poi import foo.

    (Dato che . è dentro sys.path, non abbiamo davvero bisogno di aggiungere la versione assoluta del percorso qui. Qui è dove una struttura di nidificazione dei pacchetti più profonda, dove vogliamo fare from ..otherlib.fileC import ..., fa la differenza. Se non lo fai, puoi omettere completamente tutta la sys.pathmanipolazione.)

Appunti

C'è ancora una stranezza. Se esegui l'intera cosa dall'esterno:

$ python2 lib.foo

o:

$ python3 lib.foo

il comportamento dipende dal contenuto di lib/__init__.py. Se esiste ed è vuoto , va tutto bene:

Package named 'lib'; __name__ is '__main__'

Ma se lib/__init__.py si importa in routinemodo che possa esportare routine.namedirettamente come lib.name, si ottiene:

$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'

Cioè, il modulo viene importato due volte, una volta tramite il pacchetto e poi di nuovo in __main__modo che esegua il maincodice. Python 3.6 e versioni successive avvertono di questo:

$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'

L' avvertimento è nuovo, ma non il comportamento avvertito. Fa parte di ciò che alcuni chiamano doppia trap di importazione . (Per ulteriori dettagli vedere il numero 27487 ). Nick Coghlan afferma:

La prossima trap esiste in tutte le versioni correnti di Python, incluso 3.3, e può essere riassunta nella seguente linea guida generale: "Non aggiungere mai una directory di pacchetto, o qualsiasi directory all'interno di un pacchetto, direttamente al percorso di Python".

Si noti che mentre violiamo questa regola qui, lo facciamo solo quando il file che si sta caricando non viene caricato come parte di un pacchetto e la nostra modifica è specificamente progettata per consentirci di accedere ad altri file in quel pacchetto. (E, come ho notato, probabilmente non dovremmo farlo affatto per i pacchetti a livello singolo.) Se volessimo essere estremamente puliti, potremmo riscriverlo come, ad esempio:

    import os, sys
    _i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    if _i not in sys.path:
        sys.path.insert(0, _i)
    else:
        _i = None

    from sub.fileA import f1, f2
    from sub.fileB import Class3

    if _i:
        sys.path.remove(_i)
    del _i

Cioè, modifichiamo sys.pathabbastanza a lungo per raggiungere le nostre importazioni, quindi lo rimettiamo com'era (eliminando una copia di _iif e solo se ne abbiamo aggiunta una copia _i).


7

Quindi, dopo essermi occupato di questo insieme a molti altri, mi sono imbattuto in una nota pubblicata da Dorian B in questo articolo che risolveva il problema specifico che avevo dove avrei sviluppato moduli e classi da utilizzare con un servizio web, ma voglio anche essere in grado di testarli mentre sto codificando, usando le funzionalità di debugger in PyCharm. Per eseguire i test in una classe indipendente, includerei quanto segue alla fine del mio file di classe:

if __name__ == '__main__':
   # run test code here...

ma se volessi importare altre classi o moduli nella stessa cartella, avrei dovuto cambiare tutte le mie dichiarazioni di importazione dalla notazione relativa ai riferimenti locali (cioè rimuovere il punto (.)) Ma dopo aver letto il suggerimento di Dorian, ho provato il suo ' one-liner 'e ha funzionato! Ora posso testare in PyCharm e lasciare il mio codice di test in posizione quando uso la classe in un'altra classe sotto test o quando lo uso nel mio servizio web!

# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
    from codex import Codex # these are in same folder as module under test!
    from dblogger import DbLogger
else:
    from .codex import Codex
    from .dblogger import DbLogger

L'istruzione if verifica se stiamo eseguendo questo modulo come principale o se viene utilizzato in un altro modulo che viene testato come principale . Forse questo è ovvio, ma offro questa nota qui nel caso in cui qualcun altro frustrato dai relativi problemi di importazione sopra possa farne uso.


1
Questo in realtà lo risolve. Ma è davvero brutto. Perché questo non è il comportamento predefinito ?!
Lo Tolmencre

4

Ecco una soluzione che non consiglierei, ma potrebbe essere utile in alcune situazioni in cui i moduli semplicemente non sono stati generati:

import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()

2

Ho avuto un problema simile in cui non volevo cambiare il percorso di ricerca del modulo Python e avevo bisogno di caricare un modulo relativamente da uno script (nonostante "gli script non possono importare relativamente con tutti" come BrenBarn ha spiegato bene sopra).

Quindi ho usato il seguente hack. Sfortunatamente, si basa sul impmodulo che è diventato obsoleto dalla versione 3.4 per essere abbandonato a favore importlib. (Anche questo è possibile importlib? Non lo so.) Tuttavia, l'hack funziona per ora.

Esempio per l'accesso ai membri di moduleXin subpackage1da uno script residente nella subpackage2cartella:

#!/usr/bin/env python3

import inspect
import imp
import os

def get_script_dir(follow_symlinks=True):
    """
    Return directory of code defining this very function.
    Should work from a module as well as from a script.
    """
    script_path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        script_path = os.path.realpath(script_path)
    return os.path.dirname(script_path)

# loading the module (hack, relying on deprecated imp-module)
PARENT_PATH = os.path.dirname(get_script_dir())
(x_file, x_path, x_desc) = imp.find_module('moduleX', [PARENT_PATH+'/'+'subpackage1'])
module_x = imp.load_module('subpackage1.moduleX', x_file, x_path, x_desc)

# importing a function and a value
function = module_x.my_function
VALUE = module_x.MY_CONST

Un approccio più pulito sembra essere quello di modificare il percorso sys. utilizzato per caricare i moduli come indicato da Federico.

#!/usr/bin/env python3

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    # __file__ should be defined in this case
    PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
   sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *

Sembra meglio ... peccato che richieda ancora di incorporare il nome della directory principale nel file ... forse può essere migliorato con importlib. Forse importlib può anche essere monkeypatch per rendere l'importazione relativa "solo funzionante" per casi d'uso semplici. Ci penserò io.
Andrew Wagner,

Sto usando Python 2.7.14 però. Qualcosa del genere funzionerebbe ancora?
user3474042

Ho appena testato entrambi gli approcci su Python 2.7.10 e hanno funzionato bene per me. In realtà, non si ha il problema di un modulo imp deprecato in 2.7, quindi tanto meglio.
Lars,

2

__name__ cambia a seconda che il codice in questione sia eseguito nello spazio dei nomi globale o come parte di un modulo importato.

Se il codice non è in esecuzione nello spazio globale, __name__sarà il nome del modulo. Se è in esecuzione nello spazio dei nomi globale, ad esempio, se lo si digita in una console o si esegue il modulo come uno script usando python.exe yourscriptnamehere.pyallora __name__diventa "__main__".

Vedrai un sacco di codice Python if __name__ == '__main__'utilizzato per verificare se il codice viene eseguito dallo spazio dei nomi globale, il che ti consente di avere un modulo che funge anche da script.

Hai provato a fare queste importazioni dalla console?


Ah, quindi mi dici -m. Questo fa sì che il tuo modulo venga eseguito come script - se inserisci un __name__ == '__main__' lì dentro dovresti vedere che è '__main__' a causa di -m. Prova solo a importare il tuo modulo in un altro modulo in modo che non sia il livello più alto ... che dovrebbe permetterti di fare l'importazione relativa
theodox

Ho provato a fare queste importazioni dalla console, con il file attivo che è il modulo corretto.

@Stopforgettingmyaccounts ...: Cosa intendi con "file attivo"?
BrenBarn

Uso Pyscripter. Ero in moduleX.py quando ho eseguito queste importazioni: da .moduleY import spam e da. import ModuleY.

Non importare .moduleY seguito da moduleY.spam ()?
theodox

2

La risposta di @ BrenBarn dice tutto, ma se sei come me potrebbe volerci un po 'di tempo per capire. Ecco il mio caso e come si applica la risposta di @ BrenBarn, forse ti aiuterà.

Il caso

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

Usando il nostro esempio familiare, aggiungiamo che moduleX.py ha un'importazione relativa in ..moduleA. Dato che ho provato a scrivere uno script di test nella directory subpackage1 che ha importato moduleX, ma ho ottenuto l'errore temuto descritto dall'OP.

Soluzione

Sposta lo script di test allo stesso livello del pacchetto e importa package.subpackage1.moduleX

Spiegazione

Come spiegato, le importazioni relative vengono effettuate rispetto al nome corrente. Quando il mio script di test importa moduleX dalla stessa directory, il nome del modulo all'interno di moduleX è moduleX. Quando incontra un'importazione relativa, l'interprete non può eseguire il backup della gerarchia dei pacchetti perché è già all'inizio

Quando importare moduleX dall'alto, il nome all'interno di moduleX è package.subpackage1.moduleX e la relativa importazione può essere trovata


Spero che tu mi possa guidare su questo. Nel seguente collegamento, se si passa al caso 3, si dice che la soluzione 1 non è possibile. Per favore, puoi controllare questo e fammi sapere. Mi aiuterà immensamente. chrisyeh96.github.io/2017/08/08/…
variabile

@variable c'è un refuso nel link e non mi è permesso modificarlo. Ho esaminato il caso 3 e non ho seguito esattamente quello che stai ottenendo. Quando ho provato quell'esempio in Python 2 non c'erano problemi che mi facessero pensare di aver perso qualcosa. Forse dovresti pubblicare una nuova domanda ma devi fornire un esempio più chiaro. Il caso 4 tocca ciò di cui sto parlando nella mia risposta qui: non è possibile andare in una directory per l'importazione relativa A MENO CHE l'interprete non inizi in una directory padre
Brad Dre,

Grazie, mi riferisco a Python 3 e qui la domanda stackoverflow.com/questions/58577767/…
variabile

1

Le importazioni relative utilizzano l'attributo name di un modulo per determinare la posizione di quel modulo nella gerarchia dei pacchetti. Se il nome del modulo non contiene alcuna informazione sul pacchetto (ad esempio, è impostato su "principale"), le importazioni relative vengono risolte come se il modulo fosse un modulo di livello superiore, indipendentemente da dove si trova effettivamente il modulo sul file system.

Ha scritto un piccolo pacchetto python su PyPi che potrebbe aiutare gli spettatori a questa domanda. Il pacchetto agisce come soluzione alternativa se si desidera essere in grado di eseguire file Python contenenti importazioni contenenti pacchetti di livello superiore all'interno di un pacchetto / progetto senza trovarsi direttamente nella directory del file di importazione. https://pypi.org/project/import-anywhere/


-2

Per fare in modo che Python non mi ritorni "Tentativo di importazione relativa in non pacchetto". pacchetto/

init .py subpackage1 / init .py moduleX.py moduleY.py subpackage2 / init .py moduleZ.py moduleA.py

Questo errore si verifica solo se si applica l'importazione relativa al file principale. Ad esempio, il file principale restituisce già principale dopo aver codificato "stampa ( nome )" in moduleA.py .so QUESTO file è già principalenon può restituire nessun pacchetto genitore più avanti. le importazioni relative sono richieste nei file dei pacchetti subpackage1 e subpackage2 che è possibile utilizzare ".." per fare riferimento alla directory o al modulo parent. Ma parent è se un pacchetto già di livello superiore non può andare oltre la directory parent (pacchetto). Tali file in cui si sta applicando l'importazione relativa ai genitori possono funzionare solo con l'applicazione di importazione assoluta. Se utilizzerai IMPORTANZA ASSOLUTA NEL PACCHETTO GENITORI, NESSUN ERRORE arriverà poiché Python sa chi è al livello più alto del pacchetto anche se il tuo file è in pacchetti secondari a causa del concetto di PYTHON PATH che definisce il livello più alto del progetto

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.