在类和函数间传递全局变量的替代方案

2 投票
1 回答
3840 浏览
提问于 2025-04-16 03:42

我刚开始学习Python,听说用global来传递变量给其他函数被认为是新手做法,而且还是个坏习惯。我想不再使用全局变量,但我不知道该用什么方法。

现在我在wxPython中创建了一个用户界面(UI),它是一个独立的类,还有另一个类用来从.ini文件加载设置。因为UI中的设置应该和.ini文件中的一致,我该怎么传递这些值呢?我可以用类似Settings = Settings()的方式,然后把变量定义为self.settings1,但这样我就得把Settings变成全局变量才能传给我的UI类(如果我在main()中赋值的话,它就不会是全局的)。

那么,正确且符合Python风格的传递这些变量的方法是什么呢?

编辑:这是我正在使用的代码,我想让它像Alex Martelli的例子那样工作。以下代码保存在Settings.py中:

import ConfigParser

class _Settings():
    @property
    def enableautodownload(self): return self._enableautodownload
    def __init__(self):
        self.config = ConfigParser.ConfigParser()

        self.config.readfp(open('settings.ini'))
        self._enableautodownload=self.config.getboolean('DLSettings', 'enableautodownload')

settings = _Settings()

每当我尝试从另一个文件引用Settings.settings.enableautodownload时,我都会得到:AttributeError: 'module' object has no attribute 'settings'。我哪里做错了?

编辑2:没事了,我重新输入了一遍代码,现在可以用了,可能只是简单的拼写或语法错误。

1 个回答

5

关于global变量,有很多替代方案,主要有以下几种:

  • 给函数、类传递明确的参数,比如在创建实例时传入的参数(这种方式通常最清晰,因为它让依赖关系变得非常明确,只要不是太重复就好);
  • 对象的实例变量,当需要访问这些值的函数是该对象的方法时(这也是可以的,是使用面向对象编程的合理方式);
  • 提供值的“访问函数”,或者是有属性或特性的对象。

这些方法(尤其是第一和第三种)特别适合那些名称不能被随意重绑定的值,而只能被访问。global的一个大问题是,它提供了一个“隐秘的沟通渠道”(不是指加密的意思,而是字面上的意思:看似独立的函数实际上可能依赖于彼此,通过那些在函数签名中并不“明显”的全局值相互影响——这让代码变得难以测试、调试、维护和理解)。

针对你的具体问题,如果你从不使用global语句,而是以“只读”的方式从任何地方访问设置(你可以通过将对象的属性设置为只读属性来更好地确保这一点!),那么在一个模块级别上创建一个“只读”的实例,并且这个实例只创建一次后不再改变,这样做也不错。也就是说,在某个模块foo.py中:

class _Settings(object):
    @property
    def one(self): return self._one
    @property
    def two(self): return self._two
    def __init__(self, one, two):
       self._one, self._two = one, two
settings = _Settings(23, 45)

然后在其他地方,import foo,再根据需要访问foo.settings.onefoo.settings.two。注意,我给类命名时加了一个下划线(就像这两个只读属性的实例属性一样),这表示它不应该从模块“外部”使用——只有settings对象应该被使用(这并没有强制执行——但任何违反这种隐私请求的用户显然要对可能发生的混乱负责;-)。

撰写回答