Зачем нужны модули
- Разработка большого объема кода
- командная разработка (каждый правит свой файл)
- повторное использование кода (функций)
-
можно переписать реализацию модуля, оставив только прежние названия и аргументы функций (и классов)
Программы и модули
Программа - любой файл с расширением .pyПредназначена, чтобы ее запускали. Модуль - файл с расширением .py
Могут быть модули, написанные на других языках (например, С).
Предназначены для import (или запуска как отдельного модуля)
Как работает import
Напишем программуmodule_using_sys.py
import sys print('The command line arguments are:') for i in sys.argv: print(i) print('\n\nThe PYTHONPATH is', sys.path, '\n')
$ python module_using_sys.py we are arguments # each arg is separated by white space The command line arguments are: module_using_sys.py we are arguments The PYTHONPATH is ['/tmp/py', # many entries here, not shown here '/Library/Python/2.7/site-packages', '/usr/local/lib/python2.7/site-packages']
- При выполнении import ищется запись о том, не был ли он импортирован.
- Если не был, то ищется модуль sys. Так как это встроенный модуль (build-in), то известно где его искать.
- Ищем в sys.path:
- Сначала в каталоге, где находится программа, даже если запускали ее из другого места.
- Потом из переменной окружения PYTHONPATH (если есть).
- пути к каталогам стандартной библиотеки python
-
Переменную sys.path можно изменять во время выполнения программы.
- Ищем в sys.path:
- При первом import этого модуля в программе происходит инициация модуля. Больше этот модуль не будет инициироваться. Инициализация это:
- Python выполняет скомпилированный байт-код модуля, создавая тем самым переменные, функции
-
- добавляет во внутреннюю структуру запись о том, что модуль был импортирован

python -c "import Music"Если модуля нет, то будет ошибка ImportError?.

Байт-код
Чтобы программа выполнялась быстрее, ее можно заранее скомпилировать в байт-код (.pyc) и оптимизировать (.pyo) Байт-код в питоне создается по необходимости. В других языках (Java), его нужно создавать явно. Когда интерпретатору нужен байт-код для файла myname.py:- ищет файл myname.pyo
- если не находит или находит, но старый, то ищет файл myname.pyc
- иначе скомпилирует и загрузит myname.pyc
Формы import
Чтобы использовать функцию из другого файла myfile.py нужно просто написать import myfyle import пишут вверху файла, по одному пакету на строчку. Хорошо:import os import os.path import sys
import os, os.path, sys
- стандартные библиотеки (sys, os)
- внешние библиотеки (turtle)
- свои пакеты
import имя_модуля as короткое_имя
Импортируем имя модуля и обращаемся к его функциям и переменным по имени модуль.функцияimport math import numpy as np a = math.sqrt(2) b = np.sqrt(2)
- Плюсы:
- нет конфликта имен с локальными переменными
в примере выше используем и не путаемся переменную sys.argv и argv. Это разные переменные. - нет конфликта имен с функциями с одинаковыми именами из разных пакетов.
math.sqrt и numpy.sqrt - когда читаешь код, легко понять, что это импортированная функция из какого-то (быть может внешнего) пакета.
Полезно, когда мы хотим перейти с одного внешнего пакета на другой или оценить количество работы по переходу.
- нет конфликта имен с локальными переменными
- Минусы:
- Длиннее имена, труднее читать.
from модуль import функция1, функция2, функция3
Импортируем только нужные функции и переменные. Обращаемся прямо по их именам.from math import sin, cos, pi a = sin(pi) + cos(pi)
- Плюсы:
- Проще читать алгоритм, записанный в коде.
- Минусы:
- при чтении кода не понятно, какая часть - использование внешних модулей. (Возможно понадобится при рефакторинге).
from модуль import *
Импортировать все функции и методы из этого модуля.
from math import * a = sin(pi) + cos(pi)
- если есть глобальная переменная __all__ , то только то, что перечислено в ней;
- иначе все объекты из модуля
- кроме тех, чьи имена начинаются с символа подчеркивания (_),
Конфликты имен
import os print(os.path.basename(filename)) # безопасный доступ по полным # квалифицированным именам import os.path as path print(path.basename(filename)) # есть риск конфликта имен с модулем path from os import path print(path.basename(filename)) # есть риск конфликта имен с модулем path from os.path import basename print(basename(filename)) # есть риск конфликта имен с модулем basename from os.path import * print(basename(filename)) # есть риск множественных конфликтов имен
Пакеты
Пакет – это каталог, содержащий множество модулей и файл с именем __init__.py Пусть мы написали функции, которые работают с изображениями, например, save и load. Методы для каждого формата (bmp, png, jpeg) поместили в отдельный файл Bmp.py, Png.py, Jpeg.py Все эти файлы поместили в директорию Graphics. Туда добавили пустой файл __init__.py Директория превратилась в пакет Graphics.Graphics/ __init__.py Bmp.py Jpeg.py Png.py Tiff.py Xpm.py
import Graphics
Переменная __all__

__all__ = ["Bmp", "Jpeg", "Png", "Tiff", "Xpm"]
from Graphics import * image = Xpm.load("sleepy.xpm")
Вложенные пакеты
Пусть в директории Graphics есть директория Vector с модулями Eps.py и Svg.py:Graphics/ __init__.py Bmp.py Jpeg.py Png.py Tiff.py Vector/ __init__.py Eps.py Svg.py Xpm.py
import Graphics.Vector.Eps image = Graphics.Vector.Eps.load("sneezy.eps")
Пример своего модуля
Пример взят из книги Саммерфильда, Глава 5 Модули / Модули и пакеты / Пакеты. Пример файла TextUtil?.py#!/usr/bin/env python3 # Copyright (c) 2008 Qtrac Ltd. All rights reserved. """ Этот модуль предоставляет несколько функций манипулирования строками. >>> is_balanced("(Python (is (not (lisp))))") True >>> shorten("The Crossing", 10) 'The Cro...' >>> simplify(" some text with spurious whitespace ") 'some text with spurious whitespace' """ import string def simplify(text, whitespace=string.whitespace, delete=""): r"""Возвращает текст, из которого удалены лишние пробелы. Параметр whitespace - это строка символов, каждый из которых считается символом пробела.Если параметр delete не пустой, он должен содержать строку, и тогда все символы, входящие в состав строки delete, будут удалены из строки результата. >>> simplify(" this and\n that\t too") 'this and that too' >>> simplify(" Washington D.C.\n") 'Washington D.C.' >>> simplify(" Washington D.C.\n", delete=",;:.") 'Washington DC' >>> simplify(" disemvoweled ", delete="aeiou") 'dsmvwld' """ result = [] word = "" for char in text: if char in delete: continue elif char in whitespace: if word: result.append(word) word = "" else: word += char if word: result.append(word) return " ".join(result) def shorten(text, length=25, indicator="..."): """Возвращает text или усеченную его копию с добавлением indicator в конце text – любая строка; length – максимальная длина возвращаемой строки string (включая indicator); indicator – строка, добавляемая в конец результата, чтобы показать, что текст аргумента text был усечен >>> shorten("The Road") 'The Road' >>> shorten("No Country for Old Men", 20) 'No Country for Ol...' >>> shorten("Cities of the Plain", 15, "*") 'Cities of the *' """ if len(text) > length: text = text[:length - len(indicator)] + indicator return text def is_balanced(text, brackets="()[]{}<>"): """ Проверяет баланс открывающих и закрывающих скобок в text. """ for left, right in zip(brackets[::2], brackets[1::2]): assert left != right, "the bracket characters must differ" .... дальше напишете сами, через стек на основе списка, а не через тупой подсчет количества открывающих и закрывающих :) if __name__ == "__main__": import doctest # import, который нужен только для тестирования, пишем прямо тут doctest.testmod() # выполним примеры (как - расскажем дальше)
#!/usr/bin/env python3
./TextUtil.pyПользователь может не думать, на чем написана ваша программа и чем ее запускать. Далее в """...""" - документация по модулю. Она доступна в других модулях через TextUtil.__doc__ В модуле может не быть кода вне функций. Если мы запустим такой файл как программу, то ничего не будет выполняться (только определения функций).
Модуль doctest - выполнение тестовых примеров из описаний функций
Разберем подробнее кодif __name__ == "__main__": import doctest doctest.testmod()
Trying: is_balanced("(Python (is (not (lisp))))") Expecting: True ok ... Trying: simplify(" disemvoweled ", delete="aeiou") Expecting: 'dsmvwld' ok 4 items passed all tests: 3 tests in __main__ 5 tests in __main__.is_balanced 3 tests in __main__.shorten 4 tests in __main__.simplify 15 tests in 4 items. 15 passed and 0 failed. Test passed.
Как сделать пакет доступным другим программам?
Несколько вариантов: Поместите файл TextUtils?.py в директорию- где находится программа.
- Плохо. А если нужно его использовать в нескольких разных местах? Раскладывать линки?
- в директорию
site-packages
, где установлен питон, обычно это:- C:\Python30\Lib\site-packages - Windows
- ... - Linux, MAC
- Не хорошо. Пользователь без полномочия администратора это не может сделать. Обновляем питон - сносим пакеты?
- в локальную директорию пользователя
site-packages
, обычно это:- %APPDATA%/Python/Python30/site-packages - Windows
- ~/.local/lib/python3.0/site-packages - Linux, MAC
- можно поставить локально одним пользователем
- в любую директорию. Путь к этой директории добавляем в переменную
PYTHONPATH
- можно поставить локально одним пользователем или для всех пользователей
- echo %PYTHONPATH% - посмотреть содержимое переменной, Windows
PYTHONPATH=%PYTHONPATH%;c:\python20\lib - echo $PYTHONPATH - посмотреть содержимое переменной, Linux, Mac
set PYTHONPATH=$PYTHONPATH:/usr/local/lib/python
- на лету изменяем значение переменной
sys.path
Переменная __name__. Запуск модуля как модуля и как программы.
Если мы импортируем модуль то переменная __name__ этого модуля равна имени модуля (без .py). Если мы запускаем файл как программу, то переменная __name__ принимает значение "__main__" Для чего нужно это знание? Мы можем, запуская файл только как отдельную программу, протестировать его функции. Полезно для отладки. Смотри последние строки в Сохраните этот код в файлеt1.py
if __name__ == '__main__': print('This program is being run by itself, __name__ = ', __name__) else: print('I am being imported from another module, my name =', __name__)
$python3 t1.py This program is being run by itself, __name__ = __main__
$ python3 Python 3.6.1 (default, Mar 24 2017, 12:50:34) ..... >>> import t1 I am being imported from another module, my __name__ = t1
Функция dir()
(Вставка из A bit of python, глава 11 Модули) Вы можете использовать встроенную функцию dir, чтобы получить список идентификаторов, которые объект определяет. Так в число идентификаторов модуля входят функции, классы и переменные, определённые в этом модуле. Когда вы передаёте функции dir() имя модуля, она возвращает список имён, определённых в этом модуле. Если никакого аргумента не передавать, она вернёт список имён, определённых в текущем модуле.$ python3 >>> import sys # получим список атрибутов модуля 'sys' >>> dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__', '__s tderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_compact_freelists', '_current_frames', '_getframe', 'api_version', 'argv', 'builtin_module_names', ' byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle' , 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'getcheckinterval', 'getdefaultencoding', 'getfil esystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'gettrace', 'getwindowsversion', 'hexversion', 'intern', 'maxsize', 'maxunicode ', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platfor m', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit ', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_in fo', 'warnoptions', 'winver'] >>> dir() # получим список атрибутов текущего модуля ['__builtins__', '__doc__', '__name__', '__package__', 'sys'] >>> a = 5 # создадим новую переменную 'a' >>> dir() ['__builtins__', '__doc__', '__name__', '__package__', 'a', 'sys'] >>> del a # удалим имя 'a' >>> dir() ['__builtins__', '__doc__', '__name__', '__package__', 'sys'] >>>
Относительные пути в import
PEP-328 Есть пакет pkg, состоящий из файлов:pkg/ pkg/__init__.py pkg/main.py pkg/string.py pkg/sub1 pkg/sub1/__init__.py # каждый уровень вложенности - пишем свой __init__.py pkg/sub1/hello.py
# Import names from pkg.string from .string import name1, name2 # Import pkg.string from . import string
from . import D # Imports A.B.D from .. import E # Imports A.E from ..F import G # Imports A.F.G
Запуск модуля из командной строки (ключ -m), файл __main__.py
- Для запуска файла как модуля, а не как программы:
- пишут ключ python -m (модуль)
- пишут имя файла БЕЗ расширения .py
- Чтобы запустить пакет из командной строки, в него помещают файл __main__.py
При запуске python директория выполняется именно __main__.py из этой директории.
При запуске python -m директория выполняется именно __main__.py из этой директории и до него выполняется файл __init__.py.
C-модуль
Intermediate Python, C-расширенияЗадачи
Задача 0
Напишите свою реализацию функции is_balanced из файла TestUtils?.py, добавляя очередную открывающую скобку в стек (на основе списка) и убирающую верхнюю открывающую скобку из стека, при получении закрывающей скобки.Задача 1
Файл t1.py должен запускаться как программа python t1.py и как модуль python -m t1Задача 2
Пакет pkg должен запускаться из командной строки python -m pkgЗадача 3
В модуле pkg/sub1/hello.py использовать функцию из модуля pkg/string.pyЗадача 4
Для создания задач в системе ejudge написать: 1) пакет scripts/testgen.py, который по единому файлу тестов в форматеinput1 --- output1 === input2 --- output2 ===
- ровно 23 теста, которые должны выявлять типичные ошибки при решении задачи;
- решение на С через float на котором проходят все тесты;
- решение на С через double на котором проходят все тесты;
- решение на С через int на котором НЕ проходят некоторые тесты тесты;
- решение на С через float и int на котором НЕ проходят некоторые тесты тесты;
- программа для рисования картинки - графиков с заливкой и легендой.
funk_kr +- scripts +- testgen.py - генератор тестов +- func_A - директория с задачей +- func_A.xml - условие задачи на функции +- if_A.xml - условие задачи на if +- func_A_begin.c - часть файла, которая прикрепляется системой к решению задачи на функцию +- func_A_solution.c - решение задачи на функцию +- if_A_solution.c - решение задачи на if через float (проходит все тесты) +- if_A_double_solution.c - решение задачи на if через double (проходит все тесты) +- if_A_int_fail.c - решение задачи на if через int (часть тестов не проходит) +- if_A_floatint_fail.c - решение задачи на if через float и int (часть тестов не проходит) +- test.txt - единый файл тестов для генерации +- make_pict.py - программа на питоне для рисования картинки +- tests - директория с тестами +- 001.dat - input 1-го теста +- 001.ans - эталонный output 1-го теста +- 002.dat +- 002.dat +- img - директория с картинками (создается) +- func_A.png - картинка (создается)
- При запуске с ключом -d файл make_pict.py должен рисовать график, область и наносить все точки:
- красным - лежат вне области (NO)
- зеленым - лежат в области (YES)
- (дополнительно) голубым - лежат в области, (YES), ответ сгенерен программой-решением
- (дополнительно) оранжевым - лежат вне области, (NO), ответ сгенерен программой-решением