Не вдається імпортувати Python з іншої папки


90

Здається, я не можу змусити Python імпортувати модуль у підпапці. Я отримую помилку, коли намагаюся створити екземпляр класу з імпортованого модуля, але сам імпорт вдається. Ось моя структура каталогів:

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

Ось вміст 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

І 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)

Помилка: AttributeError: об'єкт 'module' не має атрибута 'User'


1
Чи можете ви вставити повідомлення про помилку?
Harley Holcombe

Якщо з user.py, я хочу імпортувати server.py. Що мені робити?
Чандра Кант,

Відповіді:


142

Я вважаю, що вам потрібно створити файл, який називається __init__.pyв каталозі Models, щоб python розглядав його як модуль.

Тоді ви можете зробити:

from Models.user import User

Ви можете включити код в __init__.py(наприклад, код ініціалізації, який потрібен кільком різним класам) або залишити його порожнім. Але воно повинно бути там.


2
Дякую, я ніколи раніше не чув про пакунки.
ryeguy

1
Власне, під час імпортування Python порівнює blah.py та та blah / __ init__.py абсолютно однаково.
пі.

2
Це було неочевидно ... І я кажу собі: RTFM FMF
Олександр

1
Зауважте, що це не спрацює, якщо ви запускаєте server.py з іншого каталогу.
kchoi

1
що якщо server.py знаходиться в іншій папці?
Mandroid

24

Ви повинні створити __init__.pyу Modelsпідпапці. Файл може бути порожнім. Він визначає пакет.

Тоді ви можете зробити:

from Models.user import User

Прочитайте все про це у підручнику з python тут .

Існує також гарна стаття про організацію файлу пітона проектів тут .


Що робити, якщо файл НЕ порожній?
darkgaze

12

імпортувати користувача

u = user.User () # помилка в цьому рядку

Через відсутність згаданого вище __init__, ви очікуєте помилки ImportError, яка зробить проблему зрозумілішою.

Ви не отримуєте такого, оскільки "користувач" - це також існуючий модуль у стандартній бібліотеці. Ваш оператор імпорту захоплює цей і намагається знайти в ньому клас користувача; цього не існує, і лише тоді ви отримуєте помилку.

Як правило, є гарною ідеєю зробити імпорт абсолютним:

import Server.Models.user

щоб уникнути такого роду двозначності. Дійсно, з Python 2.7 'імпортер користувача' взагалі не буде виглядати відносно поточного модуля.

Якщо ви дійсно хочете відносного імпорту, ви можете мати їх явно в Python 2.5 і вище, використовуючи дещо потворний синтаксис:

from .user import User

9

Правильним способом імпорту модуля, розташованого в батьківській папці, коли у вас немає стандартної структури пакета, є:

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

(останні два рядки можна об’єднати, але цей спосіб легше зрозуміти).

Це рішення є міжплатформеним і є досить загальним, щоб його не потрібно було змінювати в інших обставинах.


7

Вам не вистачає __init__.py. З підручника з Python:

Файли __init__.py необхідні, щоб Python обробляв каталоги як такі, що містять пакунки; це робиться для запобігання каталогам із загальним іменем, таким як рядок, ненавмисно приховувати допустимі модулі, які виникають пізніше на шляху пошуку модулів. У найпростішому випадку __init__.py може бути просто порожнім файлом, але він також може виконати код ініціалізації для пакету або встановити змінну __all__, описану далі.

Помістіть порожній файл з ім'ям __init__.py у каталог Моделі, і все повинно бути золотим.


1

як виписати команду параметрів os.path.dirname....

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

0

Моїм кращим способом є __init__.py у кожному каталозі, що містить модулі, які використовуються іншими модулями, і в точці входу перевизначити sys.path, як показано нижче:

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

Це робить файли у вказаних каталогах видимими для імпорту, і я можу імпортувати користувача з Server.py.


0

Переглянувши відповіді цих співробітників вище - Zorglub29, Том, Марк, Аарон Макміллін, lucasamaral, JoeyZhao, Kjeld Flarup, Procyclinsur, martin.zaenker, tooty44 та налагодження проблеми, з якою я зіткнувся, я виявив інший випадок використання через перед яким я стикався з цим питанням. Звідси додаю мої спостереження нижче для будь-якої довідки.

У моєму коді я мав циклічний імпорт класів. Наприклад:

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)

Я отримав таку помилку, коли намагався виконати python -m pytest tests / test_utilities.py для виконання UT, написаних у 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'

Я вирішив помилку шляхом повторного розбору мого коду для переміщення функціональних можливостей у циклічному класі імпорту, щоб я міг видалити циклічний імпорт класів.

Зверніть увагу: у мене є __init__.pyфайл у моїй папці ' src ', а також папці ' tests ', і я все-таки зміг позбутися помилки ' ImportError ', просто повторно розробивши код.

Наступне посилання stackoverflow надає набагато більше подробиць про циркулярну залежність у Python .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.