Модули являются единственными действительно глобальными объектами в Python со всеми другими глобальными данными, основанными на системе модулей (которая использует sys.modules в качестве реестра). Пакеты - это просто модули со специальной семантикой для импорта подмодулей. «Компиляция» .py файла в .pyc или .pyo не является компиляцией, как это понимается для большинства языков: он только проверяет синтаксис и создает объект кода, который при выполнении в интерпретаторе создает объект модуля.
example.py:
print "Creating %s module." % __name__
def show_def(f):
print "Creating function %s.%s." % (__name__, f.__name__)
return f
@show_def
def a():
print "called: %s.a" % __name__
Интерактивная сессия:
>>> import example
# first sys.modules['example'] is checked
# since it doesn't exist, example.py is found and "compiled" to example.pyc
# (since example.pyc doesn't exist, same would happen if it was outdated, etc.)
Creating example module. # module code is executed
Creating function example.a. # def statement executed
>>> example.a()
called: example.a
>>> import example
# sys.modules['example'] found, local variable example assigned to that object
# no 'Creating ..' output
>>> d = {"__name__": "fake"}
>>> exec open("example.py") in d
# the first import in this session is very similar to this
# in that it creates a module object (which has a __dict__), initializes a few
# variables in it (__builtins__, __name__, and others---packages' __init__
# modules have their own as well---look at some_module.__dict__.keys() or
# dir(some_module))
# and executes the code from example.py in this dict (or the code object stored
# in example.pyc, etc.)
Creating fake module. # module code is executed
Creating function fake.a. # def statement executed
>>> d.keys()
['__builtins__', '__name__', 'a', 'show_def']
>>> d['a']()
called: fake.a
Ваши вопросы:
- В некотором смысле они компилируются, но не так, как вы ожидаете, если вы знакомы с работой компиляторов Си.
- Если данные неизменны, копирование возможно и должно быть неотличимо от общего доступа, за исключением идентификатора объекта (оператор
is
и id()
в Python).
- Импорт может выполнять или не выполнять код (они всегда присваивают объекту локальную переменную, но это не вызывает проблем) и может изменять или не изменять sys.modules. Вы должны быть осторожны, чтобы не импортировать потоки, и, как правило, лучше выполнять все операции импорта в верхней части каждого модуля: это приводит к каскадному графику, поэтому все операции импорта выполняются одновременно, а затем __main__ продолжается и выполняет реальную работу и торговлю; ,
- Я не знаю ни одного текущего ПКП, но там уже есть много сложных механизмов. Например, пакеты могут иметь атрибут __ path__ (на самом деле это список путей), поэтому подмодули не обязательно должны находиться в одном и том же каталоге, и эти пути можно даже вычислить во время выполнения! (Пример пакета mungepath ниже.) Вы можете иметь свои собственные ловушки импорта, использовать операторы импорта внутри функций, напрямую вызывать __import__, и я не удивлюсь, если найдет 2-3 других уникальных способа работы с пакетами и модулями.
- Подмножество системы импорта будет работать на традиционно скомпилированном языке, если оно похоже на что-то вроде C #include. Вы можете запустить «первый уровень» выполнения (создание объектов модуля) в компиляторе и скомпилировать эти результаты. Однако у этого есть существенные недостатки, которые сводятся к разным контекстам выполнения для кода уровня модуля и функций, выполняемых во время выполнения (и некоторые функции должны выполняться в обоих контекстах!). (Помните в Python, что каждый оператор выполняется во время выполнения, даже операторы def и class.)
- Я полагаю, что это является основной причиной того, что традиционно скомпилированные языки ограничивают код «верхнего уровня» объявлениями классов, функций и объектов, устраняя этот второй контекст. Даже в этом случае у вас есть проблемы с инициализацией для глобальных объектов в C / C ++ (и других), если только они не будут тщательно решены.
mungepath / __ init__.py:
print __path__
__path__.append(".") # CWD, would be different in non-example code
print __path__
from . import example # this is example.py from above, and is NOT in mungepath/
# note that this is a degenerate case, in that we now have two names for the
# 'same' module: example and mungepath.example, but they're really different
# modules with different functions (use 'is' or 'id()' to verify)
Интерактивная сессия:
>>> import example
Creating example module.
Creating function example.a.
>>> example.__dict__.keys()
['a', '__builtins__', '__file__', 'show_def', '__package__',
'__name__', '__doc__']
>>> import mungepath
['mungepath']
['mungepath', '.']
Creating mungepath.example module.
Creating function mungepath.example.a.
>>> mungepath.example.a()
called: mungepath.example.a
>>> example is mungepath.example
False
>>> example.a is mungepath.example.a
False