【问题标题】:Using a module variable within a class instance在类实例中使用模块变量
【发布时间】:2011-10-03 13:55:24
【问题描述】:

我有一个被多次实例化的类。它需要配置文件中的某个参数。我想在模块级别读取一次配置文件,以便每个实例都可以引用加载的参数。

我可能在收到邮件时遗漏了一些东西:
UnboundLocalError: local variable 'the_parameter' referenced before assignment

代码大纲如下:

import ConfigParser

config = ConfigParser.ConfigParser()
config.read('config.cfg')
the_parameter = config.getint('my_section','the_parameter')

class MyClass():
    def my_func(self):
        print(the_parameter)

【问题讨论】:

  • @S.Lott - 我添加了缺失的“自我” - 谢谢
  • class MyClass(): 看起来不对。为什么要这样做?在 Python 2 中,使用class MyClass(object):。在 Python 3 中使用 class MyClass:
  • 类定义中的括号不是必需的,除非您从另一个类继承,即。 class MyClass(object): ...class MyClass: ... 是可以接受的。
  • 我意识到我正在尝试修改全局变量 - 我认为以下问题涵盖了这一点。我投票删除我的问题stackoverflow.com/questions/423379/…
  • 把我们的我不能投票删除它,因为它有答案 - 我标记了它

标签: python module global-variables scope


【解决方案1】:

为我工作

>>> class MyClass( object ):
...     def aFunc( self ):
...         print( some_global )
... 
>>> some_global= 3
>>> x= MyClass()
>>> x.aFunc()
3

发布的代码可能删除了太多细节以显示真正的错误。

【讨论】:

  • 我刚刚遇到了一个类似的问题,这是由具有双下划线的模块变量名称引起的,如stackoverflow.com/q/21236818/1671320 所述——将变量更改为单个下划线名称即可解决此问题。
【解决方案2】:

不要试图在你的类中使用全局变量,这有点违背类的目的。如果你的类需要一个配置对象,你可以通过依赖注入传递它,即明确地将它作为参数传递给你的类:

config = ConfigParser.ConfigParser()
config.read('config.cfg')

class MyClass(object):
    def __init__(self, config):
        self._config = config

    def my_func(self):
        print self._config.getint('my_section', 'the_parameter')

顺便说一句,如果你真的只需要单个参数,你当然可以传递参数而不是整个配置对象。如果您将来可能需要其他参数,则传递 config 对象将是更好的选择。

【讨论】:

  • 这比使用无用的 global 语句要好得多,但是您的代码只有一半的 IMO 兴趣。但是,我赞成对课程目的的评论
【解决方案3】:

S.Lott 是对的:OP 的代码有效。
它可以与在类定义之前或之后定义的 the_parameter 一起使用,没关系。

当函数 my_func 作为实例之一的方法被调用时,会在 my_func 的环境中搜索对象 the_parameter 的代码块,也就是说:先在函数的本地范围内,然后在函数外,直到全局命名空间(=模块级别),因为“当一个名字在一个代码块,它使用最近的封闭范围解析。" (ref)

因此,没有必要为不存在的问题寻找解决方案。

.

但是,IMO 可以改进此代码,因为它意味着必须在全局级别绑定的所有对象中找到 the_parameter,并且这些对象可能非常多。
在函数代码中定义global the_parameter 缩短了研究过程:执行将直接在全局级别搜索对象,而无需探索函数的命名空间。

但是无论如何,在这两种情况下,这是一个糟糕的过程,与类的目的相反,正如 jena 强调的那样:实例必须是一个自给自足的对象,具有提供的字段其运作所必需的一切。

.

jena 的解决方案还不是最好的,因为它意味着每次创建实例时都必须将 the_parameter 作为参数传递。
如果 the_parameter 旨在对 MyClass 的所有实例始终通用,则代码应使其成为与 MyClass 的所有实例更严格关联的对象强>。

所以在我看来,下面的代码更方便:

class MyClass(object):
    import ConfigParser
    config = ConfigParser.ConfigParser()
    config.read('config.cfg')
    the_parameter = config.getint('my_section','the_parameter')
    del ConfigParser,config  

    def my_func(self):
        print('the_parameter == ' + str(MyClass.the_parameter)) 

这样做,the_parameter 的搜索将通过探索类的命名空间来完成,而不是在广阔的全局命名空间中。

.

更新

好吧,我意识到要找到 MyClass.the_parameter ,执行必须首先在全局命名空间中搜索对象 MyClass ,而这会破坏我所假装的。 p>

为了避免在全局命名空间中进行搜索,对实例的 _class_ 属性的调用必须这样做:

def my_func(self):
    print('the_parameter == ' + str(self.__class__.the_parameter)) 

【讨论】:

    【解决方案4】:

    global the_parameter 放入函数中以解决问题。

    【讨论】:

    • 我有点震惊这样的答案已被赞成和接受。有时,SO上有一些代码因为不尊重PEP8的小点而受到指责,但我发现这个答案的错误内容更严重。否则我对 OOP 和 Python 一无所知
    【解决方案5】:

    如果你没有将 var 声明为全局并且没有初始化它,访问未定义变量的值是错误的

    所以

    global the_parameter = config.getint(...)
    

    就是答案

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多