Python включает в себя, вопрос области видимости модуля - PullRequest
2 голосов
/ 03 февраля 2009

Я работаю над своим первым значимым проектом Python, и у меня возникают проблемы с областью видимости и выполнением кода во включаемых файлах. Ранее мой опыт работы с PHP.

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

В любом случае, я ищу общие советы о том, как лучше структурировать код для достижения того, чего я хочу.

Спасибо!

Ответы [ 5 ]

6 голосов
/ 03 февраля 2009

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

Пример: скажем, вы пишете пакет foo, который включает в себя модули bar, baz и moo.

~/project/foo
~/project/foo/__init__.py
~/project/foo/bar.py
~/project/foo/baz.py
~/project/foo/moo.py
~/project/foo/config.py

Обычно вы пишете __init__.py так:

from foo.bar import func1, func2
from foo.baz import func3, constant1
from foo.moo import func1 as moofunc1
from foo.config import *

Теперь, когда вы хотите использовать функции, которые вы просто делаете

import foo
foo.func1()
print foo.constant1
# assuming config defines a config1 variable
print foo.config1

Если вы хотите, вы можете расположить свой код так, чтобы вам нужно было только написать

import foo

Вверху каждого модуля, а затем получить доступ ко всему через foo (который вы, вероятно, должны назвать «глобальными» или что-то в этом роде). Если вам не нравятся пространства имен, вы можете даже сделать

from foo import *

и иметь все как глобальное, но это действительно не рекомендуется. Помните: пространства имен - это одна прекрасная идея!

1 голос
/ 03 февраля 2009

Это двухэтапный процесс:

  1. В вашем модуле globals.py импортируйте элементы откуда угодно.
  2. Во всех других ваших модулях выполните "из глобальных импортов *"

Приносит все эти имена в пространство имен текущего модуля.

Теперь, сказав вам, как это сделать, позвольте мне предложить вам не . Прежде всего, вы загружаете локальное пространство имен связкой «магически определенных» сущностей. Это нарушает заповедь 2 Zen of Python : «Явное лучше, чем неявное». Вместо «from foo import *» попробуйте использовать «import foo» и затем сказать «foo.some_value». Если вы хотите использовать более короткие имена, используйте «from foo import mumble, snort». Любой из этих методов напрямую раскрывает фактическое использование модуля foo.py. Использование метода globals.py - это слишком волшебно. Основным исключением является файл __init__.py, в котором вы скрываете некоторые внутренние аспекты пакета.

Глобалы также являются полусредними, поскольку очень трудно понять, кто их модифицирует (или портит). Если у вас есть четко определенные процедуры для получения / установки глобальных переменных, то их отладка может быть на намного проще.

Я знаю, что в PHP есть концепция "все едино, большое, счастливое пространство имен", но на самом деле это просто артефакт плохого языкового дизайна.

0 голосов
/ 03 февраля 2009

Другие говорили о правильном способе сделать это из Python.

Позвольте мне добавить, однако, что когда пользователи изменяют исходный файл для настройки вашего приложения, хотя это и распространено в мире PHP, это не очень Pythonic. Рассмотрите возможность использования стандартного библиотечного модуля ConfigParser или стороннего модуля ConfigObj (который поддерживает сложные типы данных, такие как вложенные символы, списки и т. Д.) Для анализа файла конфигурации.

Наличие модуля config.py, который отвечает за синтаксический анализ этого файла конфигурации, и того, какой другой код в вашем приложении импортирует и запрашивает настройки, уместно - но иметь возможность редактировать этот config.py при установке пользователем на самом деле не .

0 голосов
/ 03 февраля 2009

Это немного зависит от того, как вы хотите упаковать вещи. Вы можете мыслить с точки зрения файлов или модулей . Последний является «более питоническим» и позволяет вам точно решить, какие элементы (и они могут быть чем угодно с именем: классы, функции, переменные и т. Д.) Вы хотите сделать видимыми.

Основное правило заключается в том, что для любого импортируемого вами файла или модуля все, что находится непосредственно в его пространстве имен, доступно Так что, если myfile.py содержит определения def myfun(...): и class myclass(...), а также myvar = ..., вы можете получить к ним доступ из другого файла с помощью

import myfile
y = myfile.myfun(...)
x = myfile.myvar

или

from myfile import myfun, myvar, myclass

Важно, что на верхнем уровне myfile доступно все, , включая импорт. Так что, если myfile содержит from foo import bar, тогда также доступен myfile.bar.

0 голосов
/ 03 февраля 2009

Насколько я знаю, глобальные переменные / функции / классы / и т.д. не существует в Python, все "ограничено" в каком-то модуле (пространстве имен). Поэтому, если вы хотите, чтобы некоторые функции или классы использовались во многих частях вашего кода, одним из решений будет создание таких модулей, как: «globFunCl» (определяющий / импортирующий из другого места все, что вы хотите быть «глобальным») и «config» (содержащий конфигурацию переменных) и импортировать их везде, где они вам нужны. Если вам не нравится идея использования вложенных пространств имен, вы можете использовать:

from globFunCl import *

Таким образом, вы будете «скрывать» пространства имен (делая имена похожими на «глобальные»).

Я не уверен, что вы имеете в виду, когда не хотите " помещать всю процедуру в начало каждого (включенного) файла, чтобы включить все остальные ", боюсь, вы можете ' действительно убежать от этого. Взгляните на Python Packages , хотя они должны облегчить вам задачу.

...