Как / следует управлять глобальными данными в модулях между пакетами на Python / других языках? - PullRequest
1 голос
/ 21 декабря 2009

Я пытаюсь разработать систему пакетов и модулей для языка программирования ( Heron ), который может быть скомпилирован и интерпретирован, и из того, что я увидел, мне действительно нравится подход Python. У Python богатый выбор модулей, которые, по-видимому, в значительной степени способствуют его успеху.

Чего я не знаю, что происходит в Python, если модуль включен в два разных скомпилированных пакета: существуют ли отдельные копии данных или они передаются совместно?

С этим связан ряд побочных вопросов:

  1. Прав ли я, предполагая, что пакеты могут быть скомпилированы в Python?
  2. Каковы плюсы и минусы двух подходов (копирование или обмен данными модуля)?
  3. Существуют ли широко известные проблемы с модульной системой Python, с точки зрения сообщества Python? Например, рассматривается ли PEP для расширения модулей / пакетов?
  4. Существуют ли определенные аспекты системы модулей / пакетов Python, которые не будут хорошо работать для скомпилированного языка?

Ответы [ 3 ]

3 голосов
/ 21 декабря 2009

Ну, вы задали много вопросов. Вот несколько советов, чтобы получить немного дальше:

  1. а. Код Python лексируется и компилируется в специальные инструкции Python, но не компилируется в исполняемый код машины. Файл «.pyc» создается автоматически при каждом запуске кода Python, который не соответствует существующей временной метке .pyc. Эта функция может быть отключена. Вы можете поиграть с модулем dis, чтобы увидеть эти инструкции. б. Когда модуль импортируется, он выполняется (сверху вниз) в своем собственном пространстве имен, и это пространство имен кэшируется глобально. Когда вы импортируете из другого модуля, модуль не выполняется снова. Помните, что def - это просто утверждение. Возможно, вы захотите поместить оператор print ('compiling this module') в ваш код для его отслеживания.

  2. Зависит.

  3. Были недавние улучшения, в основном связанные с указанием, какой модуль необходимо загрузить. Модули могут иметь относительные пути, поэтому в большом проекте может быть несколько модулей с одинаковым именем.

  4. Сам Python не будет работать для скомпилированного языка. Поищите в «пустом блоге ласточки» Google, чтобы увидеть трудности, связанные с попыткой ускорить язык, где «a = sum (b)» может менять значения между казнями. Вне угловых случаев модульная система образует хороший мост между исходным кодом и скомпилированной библиотечной системой. Подход работает хорошо, и помогает простое обертывание кода Python (Swig и т. Д.).

3 голосов
/ 21 декабря 2009

Модули являются единственными действительно глобальными объектами в 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

Ваши вопросы:

  1. В некотором смысле они компилируются, но не так, как вы ожидаете, если вы знакомы с работой компиляторов Си.
  2. Если данные неизменны, копирование возможно и должно быть неотличимо от общего доступа, за исключением идентификатора объекта (оператор is и id() в Python).
  3. Импорт может выполнять или не выполнять код (они всегда присваивают объекту локальную переменную, но это не вызывает проблем) и может изменять или не изменять sys.modules. Вы должны быть осторожны, чтобы не импортировать потоки, и, как правило, лучше выполнять все операции импорта в верхней части каждого модуля: это приводит к каскадному графику, поэтому все операции импорта выполняются одновременно, а затем __main__ продолжается и выполняет реальную работу и торговлю; ,
    • Я не знаю ни одного текущего ПКП, но там уже есть много сложных механизмов. Например, пакеты могут иметь атрибут __ path__ (на самом деле это список путей), поэтому подмодули не обязательно должны находиться в одном и том же каталоге, и эти пути можно даже вычислить во время выполнения! (Пример пакета mungepath ниже.) Вы можете иметь свои собственные ловушки импорта, использовать операторы импорта внутри функций, напрямую вызывать __import__, и я не удивлюсь, если найдет 2-3 других уникальных способа работы с пакетами и модулями.
  4. Подмножество системы импорта будет работать на традиционно скомпилированном языке, если оно похоже на что-то вроде 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
1 голос
/ 21 декабря 2009

Глобальные данные находятся на уровне интерпретатора.

  1. «пакеты» могут быть скомпилированы, так как пакет - это просто набор модулей, которые сами могут быть скомпилированы.
  2. Я не уверен, что понимаю, учитывая установленный объем данных.
...