Пространства имен Python: как сделать уникальные объекты доступными в других модулях? - PullRequest
4 голосов
/ 06 сентября 2011

Я пишу PyQt-приложение среднего размера (несколько KLOC).Я начал писать его в хороших модулях для простоты понимания, но я изучаю правила пространств имен Python.В нескольких моментах важно создать экземпляр только одного объекта класса в качестве ресурса для другого кода.

Например: объект, представляющий Aspell, присоединен как подпроцесс, предлагая метод check (word).Другой пример: в приложении имеется один QTextEdit, а другой код должен вызывать методы этого единственного объекта, например, «if theEditWidget.document (). IsEmpty () ...»

. Не важно, где я это создаюобъект, на него можно ссылаться только из кода в этом модуле и ни в каком другом.Так, например, код виджета редактирования не может вызывать объект шлюза Aspell, если объект Aspell не создан в том же модуле.Прекрасно, за исключением того, что это необходимо и для других модулей.

В предлагается этот вопрос связка класс, но, как мне кажется, связка имеет точно такую ​​же проблему:это уникальный объект, который можно использовать только в том модуле, где он создан.Или я полностью скучаю по лодке здесь?

Хорошо, предложено в другом месте, это кажется простым ответом на мою проблему.Я только что проверил следующее:

junk_main.py:

import junk_A
singularResource = junk_A.thing()
import junk_B
junk_B.handle = singularResource
print junk_B.look()

junk_A.py:

class thing():
    def __init__(self):
        self.member = 99

junk_B.py:

def look():
    return handle.member

Когда я запускаю junk_main, он печатает 99. Таким образом, основной код может вводить имена в модули просто по присваиванию.Я пытаюсь придумать причины, по которым это плохая идея.

Ответы [ 3 ]

2 голосов
/ 06 сентября 2011

Оказывается, ответ проще, чем я думал. Как я отметил в этом вопросе, основной модуль может добавлять имена в импортируемый модуль. И любой код может добавить членов к объекту. Таким образом, простой способ создать область межмодульного взаимодействия - это создать базовый объект в основном, например, IMC (для межмодульного коммуникатора), и назначить ему в качестве членов все, что должно быть доступно для других модулей: *

IMC.special = A.thingy()
IMC.important_global_constant = 0x0001

и т.д.. После импорта любого модуля просто назначьте ему IMC:

import B
B.IMC = IMC

Теперь, это, вероятно, не самая лучшая идея с точки зрения разработки программного обеспечения. Если вы просто ограничите IMC хранением именованных констант, он будет действовать как файл заголовка C. Если это просто, чтобы дать доступ к единичным ресурсам, это как ссылка extern. Но из-за либеральных правил Python код в любом модуле может изменять или добавлять членов в IMC. В недисциплинированном виде «кто это изменил» может быть проблемой отладки. Если есть несколько процессов, условия гонки представляют опасность.

1 голос
/ 06 сентября 2011

В нескольких моментах важно создать экземпляр только одного объекта класса в качестве ресурса для другого кода.

Вместо того, чтобы пытаться создать какую-то одиночную фабрику, разве вы не можетесоздать одноразовый объект где-нибудь между главной точкой входа для программы и созданием объекта, который нуждается в этом?Одноразовый объект можно просто передать в качестве параметра другому объекту.Таким образом, логически вы не сможете создать одноразовый объект более одного раза.

Например:

def main(...):
    aspell_instance = ...
    myapp = MyAppClass(aspell_instance)

или ...

class SomeWidget(...):

    def __init__(self, edit_widget):
        self.edit_widget = edit_widget

    def onSomeEvent(self, ...):
        if self.edit_widget.document().isEmpty():
            ....

Iне знаю, достаточно ли это ясно или применимо к вашей ситуации.Но, честно говоря, единственный раз, когда я обнаружил, что не могу этого сделать, это веб-сервер на основе CherryPy, где точки входа были практически везде.

1 голос
/ 06 сентября 2011

Вы можете получить доступ к объектам в модуле с помощью оператора ., как и с функцией.Так, например:

# Module a.py
a = 3

>>> import a
>>> print a.a
3

Это тривиальный пример, но вы можете сделать что-то вроде:

# Module EditWidget.py
theEditWidget = EditWidget()
...

# Another module
import EditWidget

if EditWidget.theEditWidget.document().isEmpty():

Или ...

import * from EditWidget

if theEditWidget.document().isEmpty():

Если вы пойдете по маршруту import * from, вы даже можете определить список с именем __all __ в ваших модулях со списком имен (в виде строк) всех объектов, которые вы хотите экспортировать в *.,Поэтому, если вы хотите, чтобы экспортировался только EditWidget, вы можете сделать:

# Module EditWidget.py
__all__ = ["theEditWidget"]
theEditWidget = EditWidget()
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...