Найти - Пользователи
Полная версия: Относительный импорт модулей в CPython 2.6.3
Начало » Python для новичков » Относительный импорт модулей в CPython 2.6.3
1
Kogrom
Может ли мне кто-нибудь ответить на вопрос по относительному импорту модулей в CPython 2.6.3? Экспериментирую с from __future__ import absolute_import. Пока результат меня очень огорчает. Получается такая штука, если модуля нет в sys.path, но он не загружается (ошибка “Attempted relative import in non-package”).

Пытался сделать, как сказано тут:
http://www.python.org/dev/peps/pep-0328/#relative-imports-and-name

то есть создал набор пакетов со структурой:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
В файл moduleX.py вписал код:
from __future__ import absolute_import

from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from .subpackage1 import moduleY
from .subpackage2.moduleZ import eggs
Если запускаю из moduleX.py выдается ошибка:
Traceback (most recent call last):
File "...\moduleX.py", line 3, in <module>
from .moduleY import spam
ValueError: Attempted relative import in non-package
Если импортирую этот файл в moduleA.py, то всё работает. Но это не то, что мне нужно.
Александр Кошелев
Kogrom
Если импортирую этот файл в moduleA.py, то всё работает. Но это не то, что мне нужно.
В PEP есть специльное упоминание такого случая:
Relative Imports and __name__

Relative imports use a module's __name__ attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to ‘__main__’) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.
Другое дело что там не опиcано, что это будет ValueError(!) в случае наличия ‘.’ в пути.
Kogrom
Daevaorn
В PEP есть специльное упоминание такого случая
Спасибо.

Пытался исхитриться - создать модуль-переходник, с заменённым __name__. Но пока интерпретатор отказывается вестись, сообщая: Parent module ‘***’ not loaded, cannot perform relative import.

Можно ещё добавлять в sys.path верхнюю папку, но эффект будет непредсказуемым, да и вообще мне такие приёмчики не нравятся.

Ок. Вероятно, лучше всего отказаться вообще от такого импорта (если не будет крайней необходимости).
Daevaorn
Другое дело что там не опиcано, что это будет ValueError(!) в случае наличия ‘.’ в пути.
Учту.
Андрей Светлов
Не нужно хитрить.
Относительный импорт задуман для пакетов - не для “папок с файлами”.
Ваш package уже зарегестрирован в Питоне, надеюсь? distutils/setuptools/distribute
Тогда добавьте script для запуска - и все. Или python -m module, что не так красиво.
В конце-концов стоит подсмотреть, как делают другие…
Kogrom
Мы говорим немного на разных языках. Скорее всего от моей неосведомленности. Но есть вероятность, что это не так.

Я использую Python больше как учебный язык, так как с ним проще освоить применение юнит-тестов, да и с GUI-библиотеками (типа wxWidgets) проще знакомиться, чем, например, в C++.

Ну так вот я создал несколько модулей и к ним добавочные с юнит-тестами. При создании таких модулей удобно запускать их по одному, то есть чтобы модуль с юнит-тестом запускался как main и выполнял все свои тесты не смешиваясь с остальными.

Чтобы модули с юнит-тестами не путались с другими, я их хотел переместить в отдельную папку. Вроде всё понятно.

Андрей Светлов
Относительный импорт задуман для пакетов - не для “папок с файлами”.
Ваш package уже зарегестрирован в Питоне, надеюсь? distutils/setuptools/distribute
Зачем мне мои учебные модели регистрировать? Да и вообще, мне сама эта регистрация не нравится ибо она подобна гвоздю, который прибивает мои пакеты к определенному хранилищу, что уменьшает гибкость.

И относительный импорт мог бы обеспечить нужную гибкость, если бы я ссылался не на какой-то зарегистрированный пакет или модуль, а именно с помощью указания относительного пути до него.

Андрей Светлов
В конце-концов стоит подсмотреть, как делают другие…
Смотрел. Например, встроенные библиотеки, на wxPython, на IDE drpython. С первыми двумя всё понятно, а drpython хранит все свои файлы в одной папке…
Андрей Светлов
Понимаете ли, когда вы пишете import mod - этот mod должен быть как-то найден. И регистрация (установка через setup.py install/develop в простом случае) как раз это и делает.
Лучше создавать библиотеки, а не набор файлов. Это позволяет взглянуть на разработку под другим углом. И ваши вопросы отпадают.

wxPython, кстати, делает как я советую.

P.S. Для юниттестов настоятельно рекомендую http://somethingaboutorange.com/mrl/projects/nose/0.11.1/
Сможете запускать свои тесты все вместе, по одному - или в любой другой конфигурации.
Kogrom
Андрей Светлов
Понимаете ли, когда вы пишете import mod - этот mod должен быть как-то найден. И регистрация (установка через setup.py install/develop в простом случае) как раз это и делает.
Так ведь нет проблемы найти этот mod, если он в том же пакете, что и модуль в который импортируем? Тут же не требуется регистрации. И почему я не могу указать требуемый мне модуль, как я это делаю с хедерами в C ?

Нет проблем с тем чтобы найти модуль. Но, возможно, есть противоречие с некоторой идеологией, на которую намекается в следующей цитате.
Андрей Светлов
Лучше создавать библиотеки, а не набор файлов. Это позволяет взглянуть на разработку под другим углом. И ваши вопросы отпадают.
Чутьё подсказывает, что это рассуждение линуксоида. Возможно, поэтому говорится так, будто контекст всем понятен, но это не так. Например, почему библиотека не может быть незарегистрированной?

Регистрация будет нужна, если библиотекой будут пользоваться более двух программ. А до этого ещё далеко.
Андрей Светлов
wxPython, кстати, делает как я советую.
Для wxPython это естественно, так как его назначение оправдывает захламление PYTHONPATH и т. д.
Андрей Светлов
P.S. Для юниттестов настоятельно рекомендую http://somethingaboutorange.com/mrl/projects/nose/0.11.1/
Про nose читал (так как о нём упоминается в официальной документации). Инструментальные особенности меня мало интересуют, а вот некоторое упрощение, использование функций вместо классов - это хорошо. Но меня пока больше интересуют классические тесты, не заточенные под Python.
Андрей Светлов
1. Найти модуль получается потому, что питон неявно добавляет в sys.path папку, в которой лежит модуль __main__ (это тот .py, который вы запускаете).
Компромиссное решение, иногда приводящее к некоторым сложностям. Т.е. регистрация все же с точки зрения python engine есть.

2. В основном пишу для Windows, хотя и linux не чураюсь. Если у вас библиотека - так регистрируйте ее в Питоне. Статически через инсталляцию или динамически через модификацию sys.path. Можно еще и свой импортер написать/зарегистрировать. Импорт из файлов - это, по сути, только один из плагинов для стандартного механизма импорта. Сейчас он зашит прочно в код - но когда работа над importib закончится - будет просто одним из равноценных расширений, ничем особым не выделяющимся.
Для разработки очень полезно иметь библиотеки зарегистрированными в Питоне. А если хотите портабельность (скопировал файлы на любой комп - и они там работают) - стоит смотреть, например, в сторону py2exe. Ему даже установленный питон не нужен.

Это - правильный путь. Когда-то я начинал, думая примерно так же как и вы. Очевидно, что ваш подход кажется проще и “естественней”. Но это - ошибочное мнение.
Имел серию неприятных проблем. Причем чем проект больше - тем эти проблемы выползают все сильнее. Например, недавно мне потребовался почти год, чтобы понемногу перевести один очень большой проект в “библиотечную” форму, попутно с разработкой новых фич и фиксирования багов. Он начинался задолго до меня как относительно простая вещь. Возникали структурные сложности, которые решались созданием “костылей” - уникальных для каждого нового случая. И потом их было очень сложно удалять. Система выходит очень сложной и “хрупкой” - и с каждым новым модулем стоимость поддержки только растет.

3. Если быть точным - пишет wx.pth в site-packages. Не самое лучшее решение - но хоть что-то. Трогать PYTHONPATH вообще не рекомендую.

4. Видимо, у нас расхождения в терминологии. Для меня test предполагает *автоматический* анализ правильности его выполнения с выдачей информации об ошибках. Запустил - и увидел результат, не нажимая на кнопки. Для “скриптиков”, требующих взаимодействия в пользователем для ввода и анализа результатов есть термины example и demo.

Если же мы имеем в виду именно unittests в том смысле, который вкладывал в него Кент Бек - то должен заметить, что их структура сильно зависит от языка программирования. Так же как и шаблоны проектирования с идиомами программирования. Конечно, на Питоне можно писать так же, как и на C#. Но если делать “по питоновски” - часть идиом становится ненужными, код выходит проще, короче и понятней.
Бек создавал unittest для Явы - и там его структура понятна и оправданна. C# от Явы не сильно отличается - так что все переносится практически один-в-один.
Для C++ или Питона стоит использовать более приспособленные к особенностям языка средства.

К слову, nose является расширением unittest. Т.е. вы можете использовать его как куда более удобную “запускачку” тестов, продолжая писать их на unittest.
Kogrom
Андрей Светлов
1. Найти модуль получается потому, что питон неявно добавляет в sys.path папку, в которой лежит модуль __main__ (это тот .py, который вы запускаете).
Компромиссное решение, иногда приводящее к некоторым сложностям. Т.е. регистрация все же с точки зрения python engine есть.
Ну, в общем, про добавление в sys.path я говорил в первом сообщении.


Андрей Светлов
Для разработки очень полезно иметь библиотеки зарегистрированными в Питоне. А если хотите портабельность (скопировал файлы на любой комп - и они там работают) - стоит смотреть, например, в сторону py2exe. Ему даже установленный питон не нужен.
Ок. Постараюсь проникнуться этой идеологией. py2exe смотрел, испытывал, но пока оно мне не требуется.

Андрей Светлов
Если же мы имеем в виду именно unittests в том смысле, который вкладывал в него Кент Бек - то должен заметить, что их структура сильно зависит от языка программирования.

Для C++ или Питона стоит использовать более приспособленные к особенностям языка средства.
Да, я про них и говорил. В общем, и к мысли об использовании Питона пришел после прочтения книги Кента Бека про TDD (там целая глава посвящена созданию юнит-тестов на Питоне).

Ок. Спасибо. Есть информация к размышлению.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB