Переменная область за пределами классов - PullRequest
7 голосов
/ 13 октября 2011

Мой текстовый редактор по выбору расширяется с помощью плагинов Python. Это требует от меня расширения классов и переопределения его методов. Общая структура выглядит аналогично фрагменту ниже. Обратите внимание, что сигнатура функции фиксирована.

ftp_client предполагается для совместного использования экземплярами обоих классов.

ftp_client = None

class FtpFileCommand(sublime_plugin.TextCommand):
  def run(self, args):
    global ftp_client # does it reference the variable of the outer scope?
    self.ftp_client = ftplib.FTP('foo')
    # login and stuff

class FtpFileEventListener(sublime_plugin.EventListener):
  def run(self, args):
    global ftp_client # same for this
    self.ftp_client.quit() # 

Предполагается, что оба этих класса имеют одну общую переменную. Какова лучшая практика для совместного использования переменных?

Редактировать на основании ответа маджаров:

FtpFileCommand.run вызывается первым, инстанцирует ftp_client и работает как заклинание. FtpFileEventListener.run вызывается позже и может отлично ссылаться на ftp_client, но все равно None. Используя ключевое слово global, он добавляет переменную в качестве члена к self?

Ответы [ 5 ]

5 голосов
/ 13 октября 2011

Да, именно так и работает global.

Мне кажется, вы все делаете правильно, как это делается в некоторых модулях стандартной библиотеки python ( fileinput например).

4 голосов
/ 13 октября 2011

В этом коде:

global ftp_client # does it reference the variable of the outer scope?
self.ftp_client = ftplib.FTP('foo')

вы объявляете ftp_client глобальной переменной.Это означает, что он живет на уровне модуля (где, например, ваши классы).

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

Это должно быть:

global ftp_client
ftp_client = ftplib.FTP('foo')

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

class FtpFileCommand(sublime_plugin.TextCommand):
  ftp_client = None

  def run(self, args):
    FtpFileCommand.ftp_client = ftplib.FTP('foo')
    # login and stuff

Обратите внимание, что метод не использует self, поэтому он также может бытьМетод класса:

class FtpFileCommand(sublime_plugin.TextCommand):
  ftp_client = None

  @classmethod
  def run(cls, args):
    cls.ftp_client = ftplib.FTP('foo')
    # login and stuff

Таким образом, вы получите класс в качестве первого аргумента и сможете использовать его для доступа к FTP-клиенту без использования имени класса.

3 голосов
/ 13 октября 2011

Если существует только одна общая переменная, то глобальное является самым простым решением. Но обратите внимание, что переменная должна быть объявлена ​​только с global, когда она присваивается. Если глобальная переменная является объектом, вы можете вызывать ее методы, изменять ее атрибуты и т. Д., Не объявляя ее сначала глобальной.

Альтернативой использованию глобальных переменных является использование атрибутов класса, доступ к которым осуществляется с помощью методов класса. Например:

class FtpFile(object):
    _client = None

    @classmethod
    def client(cls):
        return cls._client

    @classmethod
    def setClient(cls, client):
        cls._client = client

class FtpFileCommand(FtpFile, sublime_plugin.TextCommand):
    def run(self, args):
        client = self.client()

class FtpFileEventListener(FtpFile, sublime_plugin.EventListener):
    def run(self, args):
        client = self.client()
0 голосов
/ 06 октября 2017

Як ... СПАСИБО ЗА ЭТО МНОГО !!!

Вы объявляете ftp_client глобальной переменной. Это означает, что он живет в уровень модуля (где, например, ваши классы).

Мне было трудно пытаться написать свою программу "правильно", где я использую классы и функции и не могу вызвать ни одну из переменных. Я понял, что global сделает его доступным вне класса. Когда я прочитал это, я подумал ... Если он живет вне класса, тогда переменная, которую мне нужно извлечь из скрипта py, из которого я импортирую этот модуль, будет:

module.variable

И затем в этом модуле я объявил другую глобальную переменную для вызова из основного сценария ... так пример ...

#Main Script main.py
import moduleA

print(moduleA.moduleA.variable)


#ModuleA code moduleA.py
import moduleB

class classA():

    def functionA():

      global moduleA_variable
      call.something.from.moduleB.classB.functionB()
      moduleA_variable = moduleB.moduleB_variable

Код модуля ModuleB.py

class classB():

     def functionB():

      global moduleB_variable
      moduleB_variable = retrieve.tacos()

Надеюсь, мое объяснение тоже кому-нибудь поможет. Я новичок в Python и некоторое время боролся с этим. На случай, если неясно ... У меня были отдельные пользовательские модули, составленные из нескольких разных файлов .py. Main вызывал moduleA, а moduleA вызывал moduleB. Мне пришлось вернуть переменную вверх по цепочке к основному сценарию. Смысл того, чтобы я делал это таким образом, состоял в том, чтобы по большей части содержать основной сценарий в чистоте и настраивать себя на выполнение повторяющихся задач без необходимости писать страницы дерьма. В основном пытаюсь использовать функции вместо того, чтобы писать книгу.

0 голосов
/ 13 октября 2011

Не могли бы вы добавить конструктор в каждый класс, а затем передать ftp_client в качестве аргумента?

class FtpFileCommand(sublime_plugin.TextCommand):
    ...
    def __init__(self, ftp_client):
        self.ftp_client = ftp_client
    ...

class FtpFileEventListener(sublime_plugin.EventListener):
    ...
    def __init__(self, ftp_client):
        self.ftp_client = ftp_client
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...