Impossibile ottenere che Python importi da una cartella diversa


90

Non riesco a convincere Python a importare un modulo in una sottocartella. Ricevo l'errore quando provo a creare un'istanza della classe dal modulo importato, ma l'importazione stessa riesce. Ecco la mia struttura di directory:

Server
    -server.py
    -Models
        --user.py

Ecco i contenuti di server.py:

from sys import path
from os import getcwd
path.append(getcwd() + "\\models") #Yes, i'm on windows
print path
import user

u=user.User() #error on this line

E user.py:

class User(Entity):
    using_options(tablename='users')

    username = Field(String(15))
    password = Field(String(64))
    email    = Field(String(50))
    status   = Field(Integer)
    created  = Field(DateTime)

L'errore è: AttributeError: l'oggetto 'module' non ha l'attributo 'User'


1
Puoi incollare il messaggio di errore?
Harley Holcombe

Se da user.py, voglio importare server.py. Cosa faccio?
Chandra Kanth

Risposte:


139

Credo che sia necessario creare un file chiamato __init__.pynella directory Models in modo che Python lo tratti come un modulo.

Quindi puoi fare:

from Models.user import User

È possibile includere codice in __init__.py(ad esempio codice di inizializzazione richiesto da alcune classi diverse) o lasciarlo vuoto. Ma deve essere lì.


2
Grazie, non avevo mai sentito parlare di pacchetti prima di questo.
Ryeguy

1
In realtà, quando si importa Python, blah.py ee blah / __ init__.py vengono trattati esattamente allo stesso modo.
pi.

2
Non era ovvio ... E mi dico: RTFM FMF
Alexander.Iljushkin

1
Nota che questo non funzionerà se stai eseguendo server.py da un'altra directory.
kchoi

1
cosa succede se server.py è in un'altra cartella?
Mandroid

24

Devi creare __init__.pynella Modelssottocartella. Il file potrebbe essere vuoto. Definisce un pacchetto.

Quindi puoi fare:

from Models.user import User

Leggi tutto nel tutorial di Python, qui .

C'è anche un buon articolo sull'organizzazione dei file dei progetti Python qui .


E se il file NON è vuoto?
darkgaze

12

importa utente

u = user.User () #error su questa riga

A causa della mancanza di __init__ menzionata sopra, ti aspetteresti un ImportError che renda il problema più chiaro.

Non ne ottieni uno perché anche "user" è un modulo esistente nella libreria standard. La tua dichiarazione di importazione prende quella e cerca di trovare la classe User al suo interno; che non esiste e solo allora ottieni l'errore.

In genere è una buona idea rendere assoluta l'importazione:

import Server.Models.user

per evitare questo tipo di ambiguità. Infatti da Python 2.7 "import user" non sembrerà affatto relativo al modulo corrente.

Se vuoi davvero importazioni relative, puoi averle esplicitamente in Python 2.5 e versioni successive usando la sintassi un po 'brutta:

from .user import User

9

Il modo giusto per importare un modulo che si trova in una cartella principale, quando non hai una struttura di pacchetto standard, è:

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

(puoi unire le ultime due righe ma in questo modo è più facile da capire).

Questa soluzione è multipiattaforma ed è abbastanza generale da non dover essere modificata in altre circostanze.


7

Ti manca __init__.py. Dal tutorial di Python:

I file __init__.py sono necessari per fare in modo che Python tratti le directory come contenenti pacchetti; questo viene fatto per evitare che directory con un nome comune, come stringa, nascondano involontariamente moduli validi che ricorrono successivamente nel percorso di ricerca del modulo. Nel caso più semplice, __init__.py può essere solo un file vuoto, ma può anche eseguire il codice di inizializzazione per il pacchetto o impostare la variabile __all__, descritta più avanti.

Metti un file vuoto denominato __init__.py nella directory dei modelli e tutto dovrebbe essere d'oro.


1

come scrivi il os.path.dirnamecomando parametri ....?

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

0

Il mio modo preferito è avere __init__.py su ogni directory che contiene moduli che vengono utilizzati da altri moduli e, nel punto di ingresso, sovrascrivere sys.path come di seguito:

def get_path(ss):
  return os.path.join(os.path.dirname(__file__), ss)
sys.path += [
  get_path('Server'), 
  get_path('Models')
]

Ciò rende i file nelle directory specificate visibili per l'importazione e posso importare l'utente da Server.py.


0

Dopo aver esaminato le risposte fornite da questi contributori sopra - Zorglub29, Tom, Mark, Aaron McMillin, lucasamaral, JoeyZhao, Kjeld Flarup, Procyclinsur, martin.zaenker, tooty44 e il debug del problema che stavo affrontando, ho scoperto un caso d'uso diverso a causa a cui stavo affrontando questo problema. Quindi aggiungendo le mie osservazioni di seguito per riferimento di chiunque.

Nel mio codice avevo un'importazione ciclica di classi. Per esempio:

src
 |-- utilities.py (has Utilities class that uses Event class)  
 |-- consume_utilities.py (has Event class that uses Utilities class)
 |-- tests
      |-- test_consume_utilities.py (executes test cases that involves Event class)

Ho ricevuto il seguente errore quando ho provato a eseguire python -m pytest tests / test_utilities.py per eseguire UT scritti in test_utilities.py.

ImportError while importing test module '/Users/.../src/tests/test_utilities.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_utilities.py:1: in <module>
    from utilities import Utilities
...
...
E   ImportError: cannot import name 'Utilities'

Il modo in cui ho risolto l'errore è stato rifattorizzando il mio codice per spostare la funzionalità nella classe di importazione ciclica in modo da poter rimuovere l'importazione ciclica delle classi.

Nota, ho un __init__.pyfile nella mia cartella " src " e nella cartella " tests " e sono comunque riuscito a sbarazzarmi di " ImportError " semplicemente rifattorizzando il codice.

Il seguente collegamento stackoverflow fornisce molti più dettagli sulla dipendenza circolare in Python .

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.