类外的变量作用域

10 投票
5 回答
25050 浏览
提问于 2025-04-17 04:14

我选择的文本编辑器可以通过 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() # 

这两个类应该有一个共同的变量。为了共享变量,最佳的做法是什么呢?

编辑:根据 madjars 的回答:

FtpFileCommand.run 首先被调用,实例化了 ftp_client,运行得非常顺利。接着 FtpFileEventListener.run 被调用,它可以完美地引用 ftp_client,但它仍然是 None。使用 global 关键字,这样做是否会把变量作为成员添加到 self 中呢?

5 个回答

3

如果只有一个共享的变量,那么使用全局变量是最简单的解决办法。不过要注意,只有在给这个全局变量赋值的时候,才需要用到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()
7

在这段代码中:

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 客户端,而不需要使用类名。

8

没错,这就是global的工作方式。

我觉得你这样做是对的,因为在一些Python标准库的模块中也是这样做的(比如fileinput)。

撰写回答