6. Модулі¶
Якщо ви вийшли з інтерпретатора Python і ввели його знову, зроблені вами визначення (функції та змінні) буде втрачено. Тому, якщо ви хочете написати дещо довшу програму, вам краще використовувати текстовий редактор, щоб підготувати вхідні дані для інтерпретатора, а замість цього запустити її з цим файлом як вхідними. Це відоме як створення сценарію. Коли ваша програма стає довшою, ви можете розділити її на кілька файлів для полегшення обслуговування. Ви також можете використати зручну функцію, яку ви написали в кількох програмах, не копіюючи її визначення в кожну програму.
Для підтримки цього Python має спосіб помістити визначення у файл і використовувати їх у сценарії або в інтерактивному екземплярі інтерпретатора. Такий файл називається модулем; визначення з модуля можна імпортувати в інші модулі або в головний модуль (набір змінних, до яких ви маєте доступ у сценарії, що виконується на верхньому рівні та в режимі калькулятора).
Модуль — це файл, що містить визначення та оператори Python. Ім’я файлу — це ім’я модуля з суфіксом .py
. У межах модуля ім’я модуля (у вигляді рядка) доступне як значення глобальної змінної __name__
. Наприклад, скористайтеся своїм улюбленим текстовим редактором, щоб створити файл під назвою fibo.py
у поточному каталозі з таким вмістом:
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
Тепер увійдіть до інтерпретатора Python та імпортуйте цей модуль за допомогою наступної команди:
>>> import fibo
This does not add the names of the functions defined in fibo
directly to
the current namespace (see Області та простори імен Python for more details);
it only adds the module name fibo
there. Using
the module name you can access the functions:
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
Якщо ви маєте намір часто використовувати функцію, ви можете призначити їй локальну назву:
>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
6.1. Детальніше про модулі¶
Модуль може містити виконувані оператори, а також визначення функцій. Ці оператори призначені для ініціалізації модуля. Вони виконуються лише вперше, коли ім’я модуля зустрічається в операторі імпорту. [1] (Вони також запускаються, якщо файл виконується як сценарій.)
Each module has its own private namespace, which is used as the global namespace
by all functions defined in the module. Thus, the author of a module can
use global variables in the module without worrying about accidental clashes
with a user’s global variables. On the other hand, if you know what you are
doing you can touch a module’s global variables with the same notation used to
refer to its functions, modname.itemname
.
Modules can import other modules. It is customary but not required to place all
import
statements at the beginning of a module (or script, for that
matter). The imported module names, if placed at the top level of a module
(outside any functions or classes), are added to the module’s global namespace.
There is a variant of the import
statement that imports names from a
module directly into the importing module’s namespace. For example:
>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
This does not introduce the module name from which the imports are taken in the
local namespace (so in the example, fibo
is not defined).
Існує навіть варіант імпорту всіх імен, які визначає модуль:
>>> from fibo import *
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Це імпортує всі імена, крім тих, що починаються з підкреслення (_
). У більшості випадків програмісти Python не використовують цю можливість, оскільки вона вводить невідомий набір імен в інтерпретатор, можливо, приховуючи деякі речі, які ви вже визначили.
Зауважте, що загалом практика імпортування *
з модуля чи пакету викликає негативне ставлення, оскільки це часто призводить до поганої читабельності коду. Однак його можна використовувати, щоб не вводити текст під час інтерактивних сеансів.
Якщо ім’я модуля супроводжується as
, тоді ім’я після as
прив’язується безпосередньо до імпортованого модуля.
>>> import fibo as fib
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Це фактично імпортує модуль таким же чином, як і import fibo
, з тією лише різницею, що він доступний як fib
.
Його також можна використовувати при використанні from
з подібними ефектами:
>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Примітка
З міркувань ефективності кожен модуль імпортується лише один раз за сеанс інтерпретатора. Таким чином, якщо ви змінюєте свої модулі, ви повинні перезапустити інтерпретатор – або, якщо це лише один модуль, який ви хочете протестувати в інтерактивному режимі, використайте importlib.reload()
, напр. імпорт importlib; importlib.reload(modulename)
.
6.1.1. Виконання модулів у вигляді скриптів¶
Коли ви запускаєте модуль Python з
python fibo.py <arguments>
код у модулі буде виконано так само, як якщо б ви його імпортували, але з __name__
встановленим на "__main__"
. Це означає, що додавши цей код у кінці вашого модуля:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
ви можете зробити файл придатним для використання як сценарій, а також як імпортований модуль, оскільки код, який аналізує командний рядок, запускається, лише якщо модуль виконується як «основний» файл:
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
Якщо модуль імпортовано, код не виконується:
>>> import fibo
>>>
Це часто використовується або для забезпечення зручного інтерфейсу користувача для модуля, або для цілей тестування (запуск модуля як сценарію виконує набір тестів).
6.1.2. Шлях пошуку модуля¶
When a module named spam
is imported, the interpreter first searches for
a built-in module with that name. These module names are listed in
sys.builtin_module_names
. If not found, it then searches for a file
named spam.py
in a list of directories given by the variable
sys.path
. sys.path
is initialized from these locations:
Каталог, що містить вхідний сценарій (або поточний каталог, якщо файл не вказано).
PYTHONPATH
(список імен каталогів із тим самим синтаксисом, що й змінна оболонкиPATH
).Типове значення, що залежить від встановлення (за домовленістю включає каталог
site-packages
, який обробляється модулемsite
).
More details are at The initialization of the sys.path module search path.
Примітка
У файлових системах, які підтримують символічні посилання, каталог, що містить вхідний сценарій, обчислюється після переходу за символічним посиланням. Іншими словами, каталог, що містить символічне посилання, не додається до шляху пошуку модуля.
Після ініціалізації програми Python можуть змінювати sys.path
. Каталог, що містить запущений скрипт, розміщується на початку шляху пошуку, перед стандартним шляхом до бібліотеки. Це означає, що скрипти в цьому каталозі будуть завантажені замість однойменних модулів у каталозі бібліотеки. Це помилка, якщо заміна не призначена. Перегляньте розділ Стандартні модулі для отримання додаткової інформації.
6.1.3. «Компільовані» файли Python¶
Щоб прискорити завантаження модулів, Python кешує скомпільовану версію кожного модуля в каталозі __pycache__
під назвою module.version.pyc
, де версія кодує формат скомпільованого файлу; зазвичай містить номер версії Python. Наприклад, у випуску CPython 3.3 скомпільована версія spam.py буде кешована як __pycache__/spam.cpython-33.pyc
. Ця угода про іменування дозволяє співіснувати скомпільованим модулям з різних випусків і різних версій Python.
Python порівнює дату модифікації вихідного коду зі скомпільованою версією, щоб перевірити, чи вона застаріла та потребує перекомпіляції. Це повністю автоматичний процес. Крім того, скомпільовані модулі не залежать від платформи, тому одна й та сама бібліотека може використовуватися між системами з різними архітектурами.
Python не перевіряє кеш у двох випадках. По-перше, він завжди перекомпілює і не зберігає результат для модуля, який завантажується безпосередньо з командного рядка. По-друге, він не перевіряє кеш, якщо немає вихідного модуля. Щоб підтримувати дистрибутив без вихідного коду (лише скомпільований), скомпільований модуль має бути у вихідному каталозі, а вихідного модуля не повинно бути.
Деякі поради експертам:
Ви можете використовувати перемикачі
-O
або-OO
у команді Python, щоб зменшити розмір скомпільованого модуля. Перемикач-O
видаляє оператори assert, перемикач-OO
видаляє як оператори assert, так і рядки __doc__. Оскільки деякі програми можуть покладатися на їх наявність, вам слід використовувати цей параметр, лише якщо ви знаєте, що робите. «Оптимізовані» модулі мають тегopt-
і зазвичай менші. Майбутні випуски можуть змінити результати оптимізації.Програма не працює швидше, коли вона читається з файлу
.pyc
, ніж коли вона зчитується з файлу.py
; єдине, що є швидшим у файлах.pyc
, це швидкість, з якою вони завантажуються.Модуль
compileall
може створювати файли .pyc для всіх модулів у каталозі.Більш детальну інформацію про цей процес, включаючи блок-схему рішень, можна знайти в PEP 3147.
6.2. Стандартні модулі¶
Python постачається з бібліотекою стандартних модулів, описаних в окремому документі, Довідник бібліотеки Python (далі «Довідник бібліотеки»). Деякі модулі вбудовані в інтерпретатор; вони надають доступ до операцій, які не є частиною ядра мови, але, тим не менш, вбудовані, або для ефективності, або для забезпечення доступу до примітивів операційної системи, таких як системні виклики. Набір таких модулів є опцією конфігурації, яка також залежить від базової платформи. Наприклад, модуль winreg
доступний лише в системах Windows. Один окремий модуль заслуговує на увагу: sys
, який вбудовано в кожен інтерпретатор Python. Змінні sys.ps1
і sys.ps2
визначають рядки, які використовуються як первинні та додаткові підказки:
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>
Ці дві змінні визначені, лише якщо інтерпретатор перебуває в інтерактивному режимі.
Змінна sys.path
- це список рядків, який визначає шлях пошуку модулів інтерпретатором. Він ініціалізується шляхом за замовчуванням, взятим із змінної середовища PYTHONPATH
, або з вбудованого за замовчуванням, якщо PYTHONPATH
не встановлено. Ви можете змінити його за допомогою стандартних операцій зі списком:
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
6.3. Функція dir()
¶
Вбудована функція dir()
використовується, щоб дізнатися, які імена визначає модуль. Він повертає відсортований список рядків:
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
'__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
'__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
'_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
'_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
'warnoptions']
Без аргументів dir()
перераховує імена, які ви визначили на даний момент:
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
Зверніть увагу, що в ньому перераховано всі типи імен: змінні, модулі, функції тощо.
dir()
не містить списку вбудованих функцій і змінних. Якщо вам потрібен їх список, вони визначені в стандартному модулі builtins
:
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
'FileExistsError', 'FileNotFoundError', 'FloatingPointError',
'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
'NotImplementedError', 'OSError', 'OverflowError',
'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
'__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits',
'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit',
'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass',
'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview',
'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars',
'zip']
6.4. пакети¶
Packages are a way of structuring Python’s module namespace by using «dotted
module names». For example, the module name A.B
designates a submodule
named B
in a package named A
. Just like the use of modules saves the
authors of different modules from having to worry about each other’s global
variable names, the use of dotted module names saves the authors of multi-module
packages like NumPy or Pillow from having to worry about
each other’s module names.
Припустімо, ви хочете розробити набір модулів («пакет») для однакової обробки звукових файлів і звукових даних. Існує багато різних форматів звукових файлів (зазвичай розпізнаються за їх розширенням, наприклад: .wav
, .aiff
, .au
), тому вам може знадобитися створювати та підтримувати зростаюча колекція модулів для перетворення між різними форматами файлів. Існує також багато різних операцій, які ви можете виконати зі звуковими даними (наприклад, мікшування, додавання відлуння, застосування функції еквалайзера, створення штучного стереоефекту), тож на додаток ви будете писати нескінченний потік модулів для виконання ці операції. Ось можлива структура для вашого пакета (виражена в термінах ієрархічної файлової системи):
sound/ Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
filters/ Subpackage for filters
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
Під час імпортування пакета Python шукає підкаталог пакета в каталогах sys.path
.
The __init__.py
files are required to make Python treat directories
containing the file as packages (unless using a namespace package, a
relatively advanced feature). This prevents directories with a common name,
such as string
, from unintentionally hiding valid modules that occur later
on the module search path. In the simplest case, __init__.py
can just be
an empty file, but it can also execute initialization code for the package or
set the __all__
variable, described later.
Користувачі пакету можуть імпортувати окремі модулі з пакета, наприклад:
import sound.effects.echo
This loads the submodule sound.effects.echo
. It must be referenced with
its full name.
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
Альтернативний спосіб імпорту субмодуля:
from sound.effects import echo
This also loads the submodule echo
, and makes it available without its
package prefix, so it can be used as follows:
echo.echofilter(input, output, delay=0.7, atten=4)
Ще одним варіантом є імпорт потрібної функції або змінної безпосередньо:
from sound.effects.echo import echofilter
Again, this loads the submodule echo
, but this makes its function
echofilter()
directly available:
echofilter(input, output, delay=0.7, atten=4)
Зауважте, що при використанні з елемента імпорту пакета
, елемент може бути або підмодулем (або підпакетом) пакета, або іншим ім’ям, визначеним у пакеті, як-от функція, клас або змінна. Оператор import
спочатку перевіряє, чи визначено елемент у пакеті; якщо ні, він припускає, що це модуль, і намагається його завантажити. Якщо не вдається знайти його, виникає виняток ImportError
.
Навпаки, при використанні такого синтаксису, як import item.subitem.subsubitem
, кожен елемент, крім останнього, має бути пакетом; останній елемент може бути модулем або пакетом, але не може бути класом, функцією чи змінною, визначеною в попередньому елементі.
6.4.1. Імпортування * з пакету¶
Тепер що відбувається, коли користувач пише from sound.effects import *
? В ідеалі можна було б сподіватися, що це якимось чином переходить до файлової системи, знаходить, які підмодулі присутні в пакунку, і імпортує їх усі. Це може зайняти багато часу, а імпортування субмодулів може мати небажані побічні ефекти, які мають статися лише тоді, коли субмодуль імпортовано явно.
Єдине рішення полягає в тому, щоб автор пакета надав явний індекс пакета. Інструкція import
використовує таку умову: якщо код __init__.py
пакета визначає список під назвою __all__
, він вважається списком імен модулів, які слід імпортувати, коли Зустрічається from package import *
. Автор пакета повинен підтримувати цей список актуальним, коли виходить нова версія пакета. Автори пакетів також можуть вирішити не підтримувати його, якщо вони не бачать користі для імпортування * зі свого пакета. Наприклад, файл sound/effects/__init__.py
може містити такий код:
__all__ = ["echo", "surround", "reverse"]
This would mean that from sound.effects import *
would import the three
named submodules of the sound.effects
package.
Be aware that submodules might become shadowed by locally defined names. For
example, if you added a reverse
function to the
sound/effects/__init__.py
file, the from sound.effects import *
would only import the two submodules echo
and surround
, but not the
reverse
submodule, because it is shadowed by the locally defined
reverse
function:
__all__ = [
"echo", # refers to the 'echo.py' file
"surround", # refers to the 'surround.py' file
"reverse", # !!! refers to the 'reverse' function now !!!
]
def reverse(msg: str): # <-- this name shadows the 'reverse.py' submodule
return msg[::-1] # in the case of a 'from sound.effects import *'
If __all__
is not defined, the statement from sound.effects import *
does not import all submodules from the package sound.effects
into the
current namespace; it only ensures that the package sound.effects
has
been imported (possibly running any initialization code in __init__.py
)
and then imports whatever names are defined in the package. This includes any
names defined (and submodules explicitly loaded) by __init__.py
. It
also includes any submodules of the package that were explicitly loaded by
previous import
statements. Consider this code:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
In this example, the echo
and surround
modules are imported in the
current namespace because they are defined in the sound.effects
package
when the from...import
statement is executed. (This also works when
__all__
is defined.)
Хоча певні модулі призначені для експорту лише імен, які відповідають певним шаблонам, коли ви використовуєте import *
, це все ще вважається поганою практикою у робочому коді.
Пам’ятайте, що немає нічого поганого у використанні from package import specific_submodule
! Фактично, це рекомендована нотація, якщо тільки імпортуючому модулю не потрібно використовувати підмодулі з однаковими назвами з різних пакунків.
6.4.2. Внутрішньопакетні посилання¶
When packages are structured into subpackages (as with the sound
package
in the example), you can use absolute imports to refer to submodules of siblings
packages. For example, if the module sound.filters.vocoder
needs to use
the echo
module in the sound.effects
package, it can use from
sound.effects import echo
.
You can also write relative imports, with the from module import name
form
of import statement. These imports use leading dots to indicate the current and
parent packages involved in the relative import. From the surround
module for example, you might use:
from . import echo
from .. import formats
from ..filters import equalizer
Зауважте, що відносний імпорт базується на назві поточного модуля. Оскільки назва головного модуля завжди "__main__"
, модулі, призначені для використання як головного модуля програми Python, повинні завжди використовувати абсолютний імпорт.
6.4.3. Пакунки в кількох каталогах¶
Packages support one more special attribute, __path__
. This is
initialized to be a sequence of strings containing the name of the
directory holding the
package’s __init__.py
before the code in that file is executed. This
variable can be modified; doing so affects future searches for modules and
subpackages contained in the package.
Хоча ця функція не часто потрібна, її можна використовувати для розширення набору модулів, які містяться в пакеті.
Виноски