Імпортування з відносного шляху в Python


104

У мене є папка для мого клієнтського коду, папка для мого серверного коду та папка для коду, який спільно використовується між ними

Proj/
    Client/
        Client.py
    Server/
        Server.py
    Common/
        __init__.py
        Common.py

Як імпортувати Common.py із Server.py та Client.py?


Відповіді:


140

EDIT листопада 2014 р. (3 роки потому):

Python 2.6 та 3.x підтримує належний відносний імпорт, де ви можете уникнути будь-чого хакі. За допомогою цього методу ви знаєте, що отримуєте відносний, а не абсолютний імпорт. ".." означає, перейдіть у каталог наді мною:

from ..Common import Common

Як застереження, це буде працювати лише в тому випадку, якщо ви запустите свій python як модуль, поза межами пакету. Наприклад:

python -m Proj

Оригінальний хакерський спосіб

Цей метод все ще часто використовується в деяких ситуаціях, коли ви насправді ніколи не «встановлюєте» свій пакет. Наприклад, він популярний серед користувачів Django.

Ви можете додати Common / до вашого sys.path (список шляхів, які python розглядає для імпорту речей):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) просто надає вам каталог, в якому знаходиться ваш поточний файл python, а потім ми переходимо до каталогу "Common /" та імпортуємо модуль "Common".


2
Не змінюйте шлях до модулів python вручну, можливо, це лише для швидких злому. Навчання керуванню пакетами Python за допомогою distutils, setuptools тощо, як правило, є необхідною навичкою, яка вирішить подібні проблеми.
Саша Готфрід

1
@SaschaGottfried повністю згоден, хоча якщо ви не робите розповсюджуваний пакет, це, мабуть, не буде мати значення. Наприклад, у Django ви ніколи не встановлюєте програму за допомогою distutils, тому вищевказаний спосіб є простим злому. Але в будь-якому випадку я відредагував відповідь тим, чим би займався сьогодні.
Дейв

32
Дякуємо, що відповіли на актуальне запитання, а не проповідували про правильну техніку. Існує маса вагомих причин для відносного імпорту.
землерийка

як би ви піднялися більше ніж на один рівень?
jxramos

10
щоб піднятися ще на один рівень, використовуйте додаткову крапку для кожного рівня. @jxramos ex: from ...myfileпереходить до../../myfile
WattsInABox

10

Досить смішно, та сама проблема, яку я щойно зустрічав, і я отримую цю роботу наступним чином:

поєднуючи з командою linux ln, ми можемо зробити все набагато простішим:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

А тепер, якщо ви хочете імпортувати some_stuffз file: Proj/Common/Common.pyу ваш файл:, Proj/Client/Client.pyприблизно так:

# in Proj/Client/Client.py
from Common.Common import some_stuff

І, те саме стосується Proj/Server, також працює для setup.pyпроцесу, те саме питання, яке обговорювалося тут , сподіваюся, це допоможе!


10

Не робіть відносного імпорту.

З PEP8 :

Відносного імпорту внутрішньопакетного імпорту вкрай не рекомендується.

Помістіть весь свій код в один супер-пакет (тобто "myapp") і використовуйте підпакети для клієнта, сервера та загального коду.

Оновлення: " Python 2.6 і 3.x підтримує належний відносний імпорт (...) ". Докладніше див. У відповідях Дейва .


1
Уявіть, що ви додаєте якийсь код в кінець клієнта та сервера після if __name__ == "__main__":рядка ' '. Тобто ви хочете мати можливість використовувати їх як самостійні сценарії. Як це зробити правильно? Я думаю, що це цілком поширений випадок використання, який слід підтримувати. Чому це не рекомендується?
Джабба

83
Я здивований , що «Не роби цього» є прийнятним відповіддю на «як я ...» питання (ну, для Rails <г> крім.) Там є випадкові причини , щоб зробити це. Я використовую рішення, подібне до того, що пропонує Дейв.
Том Вілсон,

1
@TomWilson: Це не чиста відповідь "не роби цього". Нижче є "зробити це таким чином".
Michał Šrajer

2
Хтось повинен сказати хлопцям у Numpy! Вони використовують ТОН відносного імпорту!
Остін А

12
Ця відповідь не стосується поточних версій Python. Цитовану частину більше не можна знайти в PEP 8. Сьогодні вона звучить так: "явний відносний імпорт є прийнятною альтернативою абсолютному імпорту, особливо коли йдеться про складні макети пакетів, де використання абсолютного імпорту було б непотрібним багатослівним"
moooeeeep

8

Робити відносний імпорт абсолютно нормально! Ось, що робить маленький «я»:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py

1
Але вам краще знати, куди насправді вказує sys.argv [0] - він (prolly) не є каталогом, в якому ви знаходились, коли запускали python.
CarlH

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

1
Це чітко написано, але оригінальний хак у відповіді Дейва є кращим, оскільки він використовує __file__для отримання належного відношення з поточного файлу
Джон Нойгаус

4

Метод імпорту за замовчуванням вже "відносний", з PYTHONPATH. PYTHONPATH є типовим для деяких системних бібліотек разом із папкою вихідного файлу. Якщо ви запускаєте модуль за допомогою -m, поточний каталог додається до PYTHONPATH. Отже, якщо точка входу вашої програми знаходиться всередині Proj, тоді використовуйтеimport Common.Common повинно працювати як у Server.py, так і в Client.py.

Не робіть відносного імпорту. Це не спрацює так, як ти хочеш.


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