Pythonpath что это
Перейти к содержимому

Pythonpath что это

  • автор:

Короче говоря: импорты в Python

У всех такое бывало: пишешь в коде import foo , а foo не импортируется, хотя вот он лежит, родненький. Чтобы уметь разбираться с такими проблемами, давайте по-быстрому разберёмся в том, как работают импорты и что там происходит. Может, узнаем что-нибудь интересного.

Начнём с простого: чем может быть foo , чтобы Питон мог его импортировать? Тут три варианта:

  • файлом foo.py ;
  • модулем (директорией foo c файлом __init__.py внутри);
  • скомпилированным модулем на Си (даже не спрашивайте).

Теперь давайте разбираться в том, как Питон понимает, что нужно импортировать именно этот foo.py и как он его находит в файловой системе. Тут всего три варианта, которые интерпретатор пытается выполнить последовательно:

  • найти нужный модуль в директории, из которой запущен изначальный скрипт;
  • найти нужный модуль в каждом из путей, указанном в PYTHONPATH ;
  • найти нужный модуль в своих хитрых питонячьих путях, которые зависят от операционной системы и том, как установлен Питон.

Чтобы стало немного понятнее: первый способ обычно срабатывает, когда мы импортируем что-то из своего проекта, а второй — когда мы импортируем чей-то сторонний пакет.

Поиск модуля в текущей директории

Давайте разберёмся с первым пунктом. Рассмотрим такой пример: мы сделали pip install requests , запускаем python script.py , а наша структура каталогов выглядит вот так:

Чуете подвох, да? Модуль requests есть и в установленных пакетах и в нашем репозитории. Когда мы сделаем import requests в script.py , какой модуль импортируется?

Ответ: импортируется наш requests.py . Потому что по алгоритму выше, интерпретатор будет сперва искать модуль в директории с запускаемым скриптом ( script.py ), а там лежит наш.

Немного усложним наш пример: заменим наш файл requests.py нашим собственным модулем requests .

Теперь при import requests все ещё используется наш модуль, но поскольку он теперь модуль, произойдёт ещё одна вещь: выполнится весь код внутри __init__.py . Если там есть запросы к базе данных — они произойдут. Если есть какой-то вывод в консоль — что-то выведется в консоль. Хотя мы ещё никакой код не выполнили, только импортировали модуль.

Поэтому по возможности не держите в __init__.py никакой логики или кода. Только другие импорты.

Поиск модуля в PYTHONPATH

PYTHONPATH — это переменная окружения, в которой хранятся пути, по которым проходится интерпретатор Питона в поисках модулей. Прям в виде строки, разделены двоеточиями (или точками с запятой, зависит от ОС).

Когда интерпретатор начинает выполнение, он парсит значение этой переменной и кладёт в sys.path :

Если очень надо сказать интерпретатору, что импортировать пакеты нужно вот из этого каталога, можно впихнуть его и в PYTHONPATH и в sys.path .

Вот, например, запуск скрипта, который первым делом будет импортировать модули из /tmp/ (непонятно, зачем это нужно, но смешно): PYTHONPATH=/tmp/:$PYTHONPATH python script.py

А вот так можно сделать то же, только внутри кода (прямо перед всеми импортами):

Важно: оба эти способа нужно использовать, когда других вариантов совсем не осталось. Обычно если вы делаете что-то такое, вы скорее всего делаете неправильно. Это не значит, что такие хаки под запретом, но если их можно избежать, то их стоит избежать.

Резюме

  • Питон ищет модули сперва в текущей директории, потом PYTHONPATH aka sys.path .
  • PYTHONPATH и sys.path можно модифицировать, но если можно этого избежать — лучше избежать.
  • Если импортируем модуль, то при его импорте выполнится весь код в __init__.py , поэтому лучше не селить в этот файл много кода.

Бонусное чтение

  • Официальная документация про модули.
  • Как работают импорты в Python.

Поиск и выполнение модулей в Python с помощью функций runpy

В этой статье мы обсудим, как пользователи могут найти модули в Python и какие функции Python используются для выполнения модулей.

Расположение модулей в Python

Когда модули импортируются пользователями, интерпретатор Python будет искать модуль в текущем каталоге. Если модуль не найден в каталоге, интерпретатор будет искать каждый каталог, присутствующий в переменной оболочки, известной как PYTHONPATH. Если интерпретатору не удается найти его в оболочке, он проверяет путь по умолчанию. В UNIX путь по умолчанию: / usr / local / lib / python /.

Путь поиска модуля хранится в системном модуле sys как переменная sys.path. Эта переменная содержит текущий каталог, то есть PYTHONPATH, и значение по умолчанию, зависящее от установки.

Переменная PYTHONPATH

PYTHONPATH — это переменная на основе платформы, которая состоит из списка каталогов. Ее синтаксис такой же, как PATH переменной оболочки.

PYTHONPATH в системе Windows:

set PYTHONPATH = c: \\python3\\lib;

PYPTHONPATH в системе UNIX:

set PYTHONPATH = /usr/local/lib/python

Выполнение модулей в Python

В параметрах командной строки параметр -m используется для определения пути к данному модулю и выполняет модуль как модуль __main__ программы. Модуль runpy — это стандартный модуль Python, который используется для внутренней поддержки этого механизма. Модуль runpy позволяет размещать сценарий, используя пространство имен модуля Python вместо файловой системы.

Модуль runpy определяет две функции:

  1. run_module()
  2. run_path()

run_module()

Функция run_module() используется для выполнения кода, содержащего конкретный модуль, и возвращает результат словаря глобальных переменных модуля.

Аргумент module_name должен быть фактическим именем модуля. Предположим, что имя модуля относится к любому пакету, а не к обычному модулю. В этом случае этот пакет будет импортирован, и подмодуль __main__ внутри пакета будет выполнен, и он вернет результат словаря глобальных переменных модуля.

Специальные глобальные переменные, то есть __name__, __spec__, __file__, __cached__, __loader__ и __package__, устанавливаются в глобальном словаре перед выполнением модуля.

__name__ устанавливается в module_name + ‘.__ main__’, если названный модуль является пакетом; в противном случае он будет установлен в аргумент имя_модуля.

И __file__, __cached__, __loader__ и __package__ устанавливаются как обычно в соответствии со спецификацией модуля.

run_path()

Функция run_path() используется для выполнения программы в файле по заданному пути, и в результате она вернет словарь глобальных переменных модуля. Указанный путь может относиться к исходному файлу Python, скомпилированному файлу байт-кода или допустимой записи sys.path, содержащей модуль __main__, например zip-файлу, включающему файл __main__.py верхнего уровня.

Специальные глобальные переменные, то есть __name__, __spec__, __file__, __cached__, __loader__ и __package__, устанавливаются в глобальном словаре перед выполнением модуля.

__name__ переменной присваивается значение run_name, если этот необязательный аргумент не равен None; в противном случае будет установлено значение .

Давайте посмотрим на пример модуля runpy:

Сначала пользователь должен сохранить следующий файл как сценарий с именем runpy_example.py.

def add(p, q, r, s, t): return p + q + r + s + t def main(): p = 4 q = 6 r = 2 s = 8 t = 7 print("sum of p, q, r, s, t EnlighterJSRAW" data-enlighter-language="python"> import runpy_example as runp runp.main()
sum of p, q, r, s, t = 27

Хотя пользователь может выполнить указанный выше файл, не импортируя его:

import runpy runpy.run_module('runpy_example', run_name='__main__')
sum of p, q, r, s, t = 27

Поиск и выполнение модулей в Python

Пользователь также может использовать функцию run_path():

runpy.run_path('runpy_example.py', run_name='__main__')
sum of p, q, r, s, t = 27

Использование функции run_path()

Как обсуждалось ранее, runpy также поддерживает переключатель -m командной строки Python:

C:\python37>python -m runpy_example

Заключение

В этой статье мы обсудили, как пользователи могут находить модули и выполнять их, используя функции модуля runpy в Python.

Покоряем Python — уроки для начинающих

и файлы .pth позволяют вам определять каталоги, где интерпретатор будет искать файлы при выполнении операции импортирования. Способ настройки переменных окружения и имена каталогов, где могут храниться файлы .pth , зависит от типа платформы. Например, в Windows можно воспользоваться ярлыком Система (System) в панели управления, чтобы записать в переменную PYTHONPATH список каталогов, разделенных точкой с запятой, как показано ниже:

c:\pycode\utilities;d:\pycode\package1
Или создать текстовый файл с именем C:\Python30\pydirs.pth , который выглядит примерно так:
c:\pycode\utilities
d:\pycode\package1
Аналогичным образом выполняются настройки и на других платформах.
Автоматическое изменение пути поиска

Это описание пути поиска модулей является верным, но достаточно общим – точная конфигурация пути поиска зависит от типа платформы и версии Python . В зависимости от используемой платформы в путь поиска модулей автоматически могут добавляться дополнительные каталоги.

Например, в путь поиска вслед за каталогами из переменной окружения PYTHONPATH и перед каталогами стандартной библиотеки интерпретатор может добавлять текущий рабочий каталог – каталог, откуда была запущена программа. Когда программа запускается из командной строки, текущий рабочий каталог может не совпадать с домашним каталогом, где находится главный файл программы (то есть с каталогом, где находится программа). Так как от запуска к запуску программы текущий рабочий каталог может изменяться, при обычных условиях рабочий каталог не должен иметь значения для операций

Чтобы увидеть, как интерпретатор настраивает путь поиска модулей на вашей платформе, вы можете проверить содержимое переменной sys.path, обсуждение которой является темой следующего поста.

Список sys.path

Если вам потребуется узнать, как выглядит путь поиска на вашей машине, вы всегда сможете сделать это, просмотрев содержимое встроенного списка sys.path . Этот список строк с именами каталогов представляет собой путь поиска, используемый интерпретатором, – при выполнении операций импорта Python просматривает каждый каталог из списка, слева направо.

Действительно, sys.path – это путь поиска модулей. Интерпретатор создает его во время запуска программы, автоматически объединяя в список домашний каталог все каталоги, перечисленные в переменной окружения PYTHONPATH и в файлах .pth , и каталоги стандартной библиотеки. В результате получается список строк с именами каталогов, которые просматриваются интерпретатором при импортировании новых файлов.

Представление языком Python этого списка имеет два основных полезных результата.

Во-первых, он обеспечивает возможность проверить настройки пути поиска, которые вы выполнили, – если вы не видите свои настройки в этом списке каталогов, вам следует проверить, насколько правильно вы все проделали. Например, ниже показано, как выглядит путь поиска модулей у меня, в операционной системе Windows в Python 3.0, с моими настройками переменной окружения PYTHONPATH , куда записан каталог C:\users , и с моим файлом C:\Python30\mypath.pth , содержащим путь к каталогу C:\users\mark . Пустая строка в начале списка соответствует текущему рабочему каталогу, а мои настройки объединены с системными (остальные пути в списке – это каталоги

стандартной библиотеки):
>>> import sys
[‘’, ‘C:\\users’, ‘C:\\Windows\\system32\\python30.zip’, ‘c:\\Python30\\DLLs’,
‘c:\\Python30\\lib’, ‘c:\\Python30\\lib\\plat-win’, ‘c:\\Python30’,
‘C:\\Users\\Mark’, ‘c:\\Python30\\lib\\site-packages’]

Во-вторых, если вы понимаете, как формируется список, вы можете обеспечить сценариям возможность самостоятельно задавать свои пути поиска. Как будет показано далее в этой части книги, изменяя список sys.path, вы можете изменить путь поиска для всех последующих операций импорта. Однако эти изменения продолжают действовать, только пока выполняется сценарий переменная окружения PYTHONPATH и файлы .pth обеспечивают возможность более долговременного хранения измененного пути.

Разобравшись с настройкой путей для модулей, в следующем посте будет показано импортирование файлов модулей

Как работают импорты в Python

Импорты не так просты, как кажется. Тем более если они пишутся для двух несовместимых версий языка. Разбираемся с основными проблемами и их решением.

Обложка поста Как работают импорты в Python

Порой бывает трудно правильно реализовать import с первого раза, особенно если мы хотим добиться правильной работы на плохо совместимых между собой версиях Python 2 и Python 3. Попытаемся разобраться, что из себя представляют импорты в Python и как написать решение, которое подойдёт под обе версии языка.

Ключевые моменты

  • Выражения import производят поиск по списку путей в sys.path .
  • sys.path всегда включает в себя путь скрипта, запущенного из командной строки, и не зависит от текущей рабочей директории.
  • Импортирование пакета по сути равноценно импортированию __init__.py этого пакета.

Основные определения

  • Модуль: любой файл *.py . Имя модуля — имя этого файла.
  • Встроенный модуль: «модуль», который был написан на Си, скомпилирован и встроен в интерпретатор Python, и потому не имеет файла *.py .
  • Пакет: любая папка, которая содержит файл __init__.py . Имя пакета — имя папки.С версии Python 3.3 любая папка (даже без __init__.py) считается пакетом.
  • Объект: в Python почти всё является объектом — функции, классы, переменные и т. д.

Пример структуры директорий

test/ # Корневая папка packA/ # Пакет packA subA/ # Подпакет subA __init__.py sa1.py sa2.py __init__.py a1.py a2.py packB/ # Пакет packB (неявный пакет пространства имён) b1.py b2.py math.py random.py other.py start.py 

Обратите внимание, что в корневой папке test/ нет файла __init__.py .

Что делает import

При импорте модуля Python выполняет весь код в нём. При импорте пакета Python выполняет код в файле пакета __init__.py , если такой имеется. Все объекты, определённые в модуле или __init__.py , становятся доступны импортирующему.

Встроенные функции Python: какие нужно знать и на какие не стоит тратить время

Основы import и sys.path

Вот как оператор import производит поиск нужного модуля или пакета согласно документации Python:

    t
  • директории, содержащей исходный скрипт (или текущей директории, если файл не указан); t
  • директории по умолчанию, которая зависит от дистрибутива Python; t
  • PYTHONPATH (список имён директорий; имеет синтаксис, аналогичный переменной окружения PATH ).

Технически документация не совсем полна. Интерпретатор будет искать не только файл (модуль) spam.py , но и папку (пакет) spam .

Обратите внимание, что Python сначала производит поиск среди встроенных модулей — тех, которые встроены непосредственно в интерпретатор. Список встроенных модулей зависит от дистрибутива Python, а найти этот список можно в sys.builtin_module_names (Python 2 и Python 3). Обычно в дистрибутивах есть модули sys (всегда включён в дистрибутив), math , itertools , time и прочие.

В отличие от встроенных модулей, которые при поиске проверяются первыми, остальные (не встроенные) модули стандартной библиотеки проверяются после директории запущенного скрипта. Это приводит к сбивающему с толку поведению: возможно «заменить» некоторые, но не все модули стандартной библиотеки. Допустим, модуль math является встроенным модулем, а random — нет. Таким образом, import math в start.py импортирует модуль из стандартной библиотеки, а не наш файл math.py из той же директории. В то же время, import random в start.py импортирует наш файл random.py .

Кроме того, импорты в Python регистрозависимы: import Spam и import spam — разные вещи.

Функцию pkgutil.iter_modules() (Python 2 и Python 3) можно использовать, чтобы получить список всех модулей, которые можно импортировать из заданного пути:

import pkgutil search_path = ['.'] # Используйте None, чтобы увидеть все модули, импортируемые из sys.path all_modules = [x[1] for x in pkgutil.iter_modules(path=search_path)] print(all_modules) 

Чуть подробнее о sys.path

Чтобы увидеть содержимое sys.path , запустите этот код:

import sys print(sys.path) 

Документация Python описывает sys.path так:

Список строк, указывающих пути для поиска модулей. Инициализируется из переменной окружения PYTHONPATH и директории по умолчанию, которая зависит от дистрибутива Python.При запуске программы после инициализации первым элементом этого списка, path[0] , будет директория, содержащая скрипт, который был использован для вызова интерпретатора Python. Если директория скрипта недоступна (например, если интерпретатор был вызван в интерактивном режиме или скрипт считывается из стандартного ввода), то path[0] является пустой строкой. Из-за этого Python сначала ищет модули в текущей директории. Обратите внимание, что директория скрипта вставляется перед путями, взятыми из PYTHONPATH .Источник: Python 2 и Python 3

Документация к интерфейсу командной строки Python добавляет информацию о запуске скриптов из командной строки. В частности, при запуске python .py .

Если имя скрипта ссылается непосредственно на Python-файл, то директория, содержащая этот файл, добавляется в начало sys.path , а файл выполняется как модуль main .Источник: Python 2 и Python 3

Итак, повторим порядок, согласно которому Python ищет импортируемые модули:

  1. Модули стандартной библиотеки (например, math , os ).
  2. Модули или пакеты, указанные в sys.path :Если интерпретатор Python запущен в интерактивном режиме:sys.path[0] — пустая строка ». Это значит, что Python будет искать в текущей рабочей директории, из которой вы запустили интерпретатор. В Unix-системах эту директорию можно узнать с помощью команды pwd.Если мы запускаем скрипт командой python

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *