Я хочу наследовать от класса в файле, который находится в каталоге выше текущего.
Можно ли относительно импортировать этот файл?
Я хочу наследовать от класса в файле, который находится в каталоге выше текущего.
Можно ли относительно импортировать этот файл?
Ответы:
from ..subpkg2 import mod
Согласно документации по Python: внутри иерархии пакетов используйте две точки, как сказано в документе import import :
При указании модуля для импорта не нужно указывать абсолютное имя модуля. Когда модуль или пакет содержится в другом пакете, можно сделать относительный импорт в том же самом верхнем пакете, не упоминая имя пакета. Используя начальные точки в указанном модуле или пакете после,
from
вы можете указать, как высоко пройти по текущей иерархии пакетов без указания точных имен. Одна начальная точка означает текущий пакет, в котором существует модуль, выполняющий импорт. Две точки означают один уровень пакета . Три точки выше двух уровней и т. Д. Итак, если вы выполняетеfrom . import mod
из модуля вpkg
пакете, то в итоге вы импортируетеpkg.mod
. Если вы выполните . Спецификация для относительного импорта содержится вfrom ..subpkg2 import mod
изнутри,pkg.subpkg1
вы будете импортироватьpkg.subpkg2.mod
PEP 328 .
PEP 328 имеет дело с абсолютным / относительным импортом.
import sys
sys.path.append("..") # Adds higher directory to python modules path.
Ответ @ gimel верен, если вы можете гарантировать иерархию пакетов, о которой он говорит. Если вы не можете - если ваша реальная потребность в том виде, в каком вы ее выразили, привязана исключительно к каталогам и не имеет никакого отношения к упаковке - тогда вам нужно поработать, __file__
чтобы выяснить родительский каталог ( os.path.dirname
подойдет пара вызовов; -), затем (если этот каталог еще не sys.path
включен) prepend временно вставляет указанный dir в самом начале sys.path
, __import__
снова удаляет указанный dir - грязная работа действительно, но, «когда вы должны, вы должны» (и Pyhon стремится никогда не мешайте программисту делать то, что должно быть сделано - как сказано в стандарте ISO C в разделе «Дух 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)
после импорта, которое вам нужно, чтобы не сохранять этот новый путь.
Импортировать модуль из каталога, который находится ровно на один уровень выше текущего каталога:
from .. import module
from .. import module
Я получил ошибку ValueError: Попытка относительного импорта в не-пакет , следуя рекомендации
Предисловие: я существенно переписал предыдущий ответ, надеясь помочь облегчить людям доступ к экосистеме python и, надеюсь, дать каждому наилучшее изменение успеха с помощью системы импорта 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 в среду, в которой нет файловой системы defacto без предоставления виртуальной, например, 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, однако вы можете написать конфигурацию для изменения / перенаправления всего, что setuptools делает по умолчанию, если хотите; например, размещение 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/
«редактируемый» aka -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'],
)
Мне также нравится делать a 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
Если вы выпускаете артефакт сборки, например, копию кода, предназначенного для запуска практически идентичных компьютеров, файл require.txt - это популярный способ получения точной информации о зависимостях, где «install_requires» - это хороший способ собрать минимум и максимально совместимые версии. Однако, учитывая, что целевые машины в любом случае почти идентичны, я настоятельно рекомендую создать тарбол с полным префиксом python. Это может быть сложно, слишком подробно, чтобы попасть сюда. Проверьте pip install
's --target
вариант, или virtualenv aka venv для лидов.
вернуться к примеру
Из foo / spam / eggs.py, если мы хотим получить код из foo / baz, мы можем запросить его по абсолютному пространству имен:
import foo.baz
Если бы мы хотели зарезервировать возможность в будущем переместить eggs.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_modules и пакеты
#!/usr/bin/env python3
import bar
import foo
print(dir(bar))
print(dir(foo))
pip install --edit foo
, почти всегда внутри virtualenv. Я почти никогда не пишу модуль, который не предназначен для установки. если я что-то неправильно понимаю, я хотел бы знать.
editable
ссылки на egg и установленные модули python не совсем одинаковы во всех отношениях; например, добавление нового пространства имен в редактируемый модуль будет найдено в вашем пути поиска, но если это не экспортируется в ваш файл setup.py, он не будет упакован / установлен! Проверьте ваш вариант использования :)