Я хочу успадкувати від класу у файлі, який лежить у каталозі над поточним.
Чи можна відносно імпортувати цей файл?
Я хочу успадкувати від класу у файлі, який лежить у каталозі над поточним.
Чи можна відносно імпортувати цей файл?
Відповіді:
from ..subpkg2 import mod
За документами Python: Коли всередині ієрархії пакета використовуйте дві крапки, як говорить документ імпорту документа:
Вказуючи, який модуль імпортувати, не потрібно вказувати абсолютну назву модуля. Якщо модуль або пакунок містяться в іншому пакеті, можна здійснити відносний імпорт всередині того самого верхнього пакету, не згадуючи імені пакета. Використовуючи провідні точки у вказаному модулі чи пакеті,
fromви зможете вказати, наскільки високою є обхід поточної ієрархії пакетів, не вказуючи точних назв. Одна провідна точка означає поточний пакет, де існує модуль, що здійснює імпорт. Дві крапки означає один рівень упаковки . Три точки - це два рівні тощо. Отже, якщо ви виконаєтеfrom . import modз модуля вpkgпакеті, тоді ви закінчите імпортуватиpkg.mod. Якщо ви виконуєте . Специфікація відносного імпорту міститься в межахfrom ..subpkg2 import modзсередини,pkg.subpkg1ви імпортуєтеpkg.subpkg2.modPEP 328 .
PEP 328 стосується абсолютного / відносного імпорту.
import sys
sys.path.append("..") # Adds higher directory to python modules path.
@ gimel відповідь правильна, якщо ви можете гарантувати ієрархію пакунків, яку він згадує. Якщо ви не можете - якщо ваша реальна потреба така, як ви її висловили, прив'язана виключно до каталогів і не має ніякого необхідного відношення до упаковки - тоді вам потрібно працювати над тим, __file__щоб дізнатися батьківський каталог (пара os.path.dirnameдзвінків зробиться; -), а потім (якщо цей каталог не включене sys.path) перед ім'ям тимчасової вставки сказала реж на самому початку sys.path, __import__, видалити знову сказав реж - брудну роботи на самому справі, але, «коли ви повинні, ви повинні» (і Pyhon прагне ніколи не перешкоджайте програмісту робити те, що потрібно зробити - як саме стандарт ISO C говорить у розділі "Дух С" у передмові! -).
Ось приклад, який може працювати для вас:
import sys
import os.path
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
import module_in_parent_dir
sys.pathтаким чином, щоб той самий модуль був доступний під різними іменами та всіма відповідними помилками. autopath.py в pypy або _preamble.py у крученому вирішіть це за допомогою критеріїв пошуку, що визначає пакет верхнього рівня, переходячи до каталогів вгору.
sys.path.remove(pathYouJustAdded)після потрібного імпорту, щоб не зберегти цей новий шлях.
передмова: Я істотно переписав попередню відповідь, сподіваючись допомогти людям ввійти в екосистему пітона, і сподіваюся, що всім найкраща зміна успіху в системі імпорту python.
Це стосуватиметься відносного імпорту в рамках пакету , що, на мою думку, є найбільш ймовірним випадком на питання ОП.
Ось чому ми пишемо import fooдля завантаження модуля "foo" з кореневого простору імен, а не для написання:
foo = dict(); # please avoid doing this
with open(os.path.join(os.path.dirname(__file__), '../foo.py') as foo_fh: # please avoid doing this
exec(compile(foo_fh.read(), 'foo.py', 'exec'), foo) # please avoid doing this
Ось чому ми можемо вбудовувати python у середовище, де немає файлової системи дефакто, не надаючи віртуальну, наприклад, Jython.
Розв’язаний з файлової системи дозволяє імпорту бути гнучким, цей дизайн дозволяє такі речі, як імпорт з архівів / zip-файлів, імпортувати одинакових клавіш, кешування байтових кодів, розширення cffi, навіть завантаження визначення коду.
Отже, якщо імпорт не пов'язаний з файловою системою, що означає "один каталог"? Нам потрібно вибрати деякі евристики, але ми можемо це зробити, наприклад, працюючи в рамках пакету , деякі евристики вже визначені, що робить відносний імпорт подібним .fooі..foo працює в межах одного пакету. Класно!
Якщо ви щиро хочете з'єднати шаблони завантаження вихідного коду з файловою системою, можете це зробити. Вам доведеться вибрати власну евристику та використовувати якусь імпортну техніку, рекомендую імпортну importlib
Приклад importlib Python виглядає приблизно так:
import importlib.util
import sys
# For illustrative purposes.
file_path = os.path.join(os.path.dirname(__file__), '../foo.py')
module_name = 'foo'
foo_spec = importlib.util.spec_from_file_location(module_name, file_path)
# foo_spec is a ModuleSpec specifying a SourceFileLoader
foo_module = importlib.util.module_from_spec(foo_spec)
sys.modules[module_name] = foo_module
foo_spec.loader.exec_module(foo_module)
foo = sys.modules[module_name]
# foo is the sys.modules['foo'] singleton
Офіційний проект-приклад доступний тут: https://github.com/pypa/sampleproject
Пакет python - це сукупність інформації про ваш вихідний код, яка може інформувати інші інструменти, як скопіювати свій вихідний код на інші комп’ютери та як інтегрувати свій вихідний код у шлях до системи, щоб він import fooпрацював для інших комп'ютерів (незалежно від інтерпретатора, хост-операційна система тощо)
Дозволяє мати назву пакета fooв деякому каталозі (бажано, порожній каталог).
some_directory/
foo.py # `if __name__ == "__main__":` lives here
Я вважаю за краще створити setup.pyяк рідний брат foo.py, оскільки це спрощує написання файла setup.py простішим, проте ви можете написати конфігурацію, щоб змінити / перенаправити все, що налаштування робить за замовчуванням; наприклад, розміщення foo.pyпід каталогом "src /" є дещо популярним, тут не висвітлено.
some_directory/
foo.py
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
py_modules=['foo'],
)
.
python3 -m pip install --editable ./ # or path/to/some_directory/
"редаговане" ака -eще знову перенаправить імпортуючу машину для завантаження вихідних файлів у цей каталог, замість цього скопіюючи поточні точні файли в бібліотеку середовища інсталяції. Це також може спричинити відмінності в поведінці на машині розробника, не забудьте протестувати свій код! Є інші інструменти, крім pip, проте я рекомендую, щоб pip був вступним :)
Мені також подобається зробити foo"пакунок" (каталог, що містить __init__.py) замість модуля (єдиний файл ".py"), і "пакети", і "модулі" можна завантажувати в кореневу область імен, модулі дозволяють вкладені простори імен, що корисно, якщо ми хочемо імпортувати "відносний один каталог".
some_directory/
foo/
__init__.py
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
packages=['foo'],
)
Мені також подобається зробити це foo/__main__.py, це дозволяє python виконувати пакет як модуль, наприклад python3 -m foo, виконуватиме foo/__main__.pyяк __main__.
some_directory/
foo/
__init__.py
__main__.py # `if __name__ == "__main__":` lives here, `def main():` too!
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
packages=['foo'],
...
entry_points={
'console_scripts': [
# "foo" will be added to the installing-environment's text mode shell, eg `bash -c foo`
'foo=foo.__main__:main',
]
},
)
Дозволяє обгрунтувати це з допомогою декількох модулів: В основному, ви можете мати структуру каталогів так:
some_directory/
bar.py # `import bar`
foo/
__init__.py # `import foo`
__main__.py
baz.py # `import foo.baz
spam/
__init__.py # `import foo.spam`
eggs.py # `import foo.spam.eggs`
setup.py
setup.py умовно зберігає інформацію метаданих про вихідний код у межах, таких як:
foo , хоча заміна підкреслення для дефісів є популярноюpython ./setup.py testЦе дуже експансивно, він може навіть збирати розширення c на льоту, якщо на розроблювальній машині встановлюється вихідний модуль. Для прикладу щодня я рекомендую setup.py репозиторію зразків PYPA
Якщо ви випускаєте артефакт збірки, наприклад копію коду, який призначений для роботи майже однакових комп'ютерів, файл вимоги.txt - це популярний спосіб знімати точну інформацію про залежність, де "install_requires" - хороший спосіб зафіксувати мінімум та максимально сумісні версії. Однак, враховуючи, що цільові машини в будь-якому випадку майже однакові, я настійно рекомендую створити тарбол цілого префікса python. Це може бути складним, надто детальним, щоб потрапити сюди. Перевірте pip install«S--target варіант, або virtualenv ака venv для потенційних клієнтів.
повернутися до прикладу
З foo / spam / egg.py, якщо нам потрібен код з foo / baz, ми могли б попросити його за його абсолютним простором імен:
import foo.baz
Якщо ми хотіли б зарезервувати можливість переміщення egg.py в якийсь інший каталог в майбутньому з іншою відносною bazреалізацією, ми могли б використовувати відносний імпорт, наприклад:
import ..baz
Щоб надійно завантажити код python, встановіть цей код у модулі та цей модуль, встановлений у бібліотеці python.
Встановлені модулі завжди можна завантажувати з простору імен верхнього рівня import <name>
Офіційно представлений чудовий зразок проекту: https://github.com/pypa/sampleproject
В основному, ви можете мати структуру каталогів так:
the_foo_project/
setup.py
bar.py # `import bar`
foo/
__init__.py # `import foo`
baz.py # `import foo.baz`
faz/ # `import foo.faz`
__init__.py
daz.py # `import foo.faz.daz` ... etc.
.
Обов'язково оголосити setuptools.setup()по прибуттю setup.py,
офіційний приклад: https://github.com/pypa/sampleproject/blob/master/setup.py
У нашому випадку ми, мабуть, хочемо експортувати, bar.pyі foo/__init__.pyмій короткий приклад:
#!/usr/bin/env python3
import setuptools
setuptools.setup(
...
py_modules=['bar'],
packages=['foo'],
...
entry_points={},
# Note, any changes to your setup.py, like adding to `packages`, or
# changing `entry_points` will require the module to be reinstalled;
# `python3 -m pip install --upgrade --editable ./the_foo_project
)
.
Тепер ми можемо встановити наш модуль у бібліотеку python; за допомогою pip ви можете встановити the_foo_projectу свою бібліотеку python в режимі редагування, щоб ми могли над цим працювати в режимі реального часу
python3 -m pip install --editable=./the_foo_project
# if you get a permission error, you can always use
# `pip ... --user` to install in your user python library
.
Тепер з будь-якого контексту python ми можемо завантажити наші спільні py_модулі та пакети
#!/usr/bin/env python3
import bar
import foo
print(dir(bar))
print(dir(foo))
pip install --edit foo, майже завжди всередині virtualenv. Я майже ніколи не пишу модуль, який не передбачається встановлювати. якщо я неправильно розумію щось, що хотів би знати.
editableпосилання на яйця та встановлені модулі пітона не є абсолютно однаковими у всіх напрямках; Наприклад, додавання нового простору імен до редагованого модуля буде знайдено у вашому пошуку шляху, але якщо це не експортується у вашому файлі setup.py, воно не буде упаковано / встановлено! Перевірте свій випадок використання :)