【问题标题】:Python scoping issue with dictionary comprehension inside class level code类级代码中字典理解的 Python 范围界定问题
【发布时间】:2014-05-12 09:59:17
【问题描述】:

小例子

class foo:
    loadings = dict(hi=1)
    if 'hi' in loadings:
        print(loadings['hi']) 
        # works
        print({e : loadings[e] for e in loadings})
        # NameError global name 'loadings' not defined

我也尝试过引用类命名空间,但这也不起作用

class foo:
    loadings = dict(hi=1)
    if 'hi' in loadings:
        print(loadings['hi'])
        #works
        print({e : foo.loadings[e] for e in foo.loadings})
        #NameError: name 'foo' is not defined

当然,这是按预期工作的

class foo:
    loadings = dict(hi=1)
    if 'hi' in loadings:
        print(loadings['hi'])

print({e : foo.loadings[e] for e in foo.loadings})

我想了解为什么会出现这个范围问题,如果我想做一些疯狂的事情,请了解最好的方法。我的感觉是第一个代码片段应该按原样工作,但当然不是。

目标

我正在为一些 csv/json 文件以及罐装数据库查询创建一个 DataManager 类/模块,为我的程序和获取数据提供一站式服务。有一些静态数据和一些动态数据,所以在同一个类中似乎很好地使用了静态和非静态数据成员。虽然我知道这些可能是模块级变量,但我喜欢拥有静态类数据成员的概念(可能是因为 Java 的偏见)。非常感谢任何帮助

我的解决方案(目前)

我最终展开列表理解以保持在类范围内,在上面它会变成这样

class foo:
    loadings = dict(hi=1)
    temp = dict()
    for e in loadings:
        temp[e] = loadings[e] # keep in mind this is a minimal example, I probably wouldn't do (just) this
    print(temp) # works
    del temp

它不漂亮,但现在可以使用

【问题讨论】:

  • 你应该在初始化函数中完成所有这些......
  • 我认为注意到print({k: v for k, v in loadings.items()}) 确实有效也很有趣。所以loadings 在字典理解中至少有点可见
  • 这没有在 init 函数中完成,因为这是加载一次的类的静态数据。我可以有一些像runonce 之类的标志,但似乎类级代码的存在是有原因的。

标签: python json csv scoping


【解决方案1】:

根据Name and Binding docs

类块中定义的名称范围仅限于类 堵塞;它没有扩展到方法的代码块——this 包括推导式和生成器表达式,因为它们是 使用函数范围实现。这意味着以下将 失败:

class A:
    a = 42
    b = list(a + i for i in range(10))

更多详情请见this answer


在 Python2 中,可以使用列表推导,因为它们是在没有使用函数范围的情况下实现的:

dict([(e,loadings[e]) for e in loadings])

但如果在 Python3 中运行,此代码会中断。因此,这是一种适用于 Python2 和 Python3 的替代解决方法:

class Foo:
    def loadings():
        load = dict(hi=1)
        if 'hi' in load:
            print(load['hi']) 
            print({e:load[e] for e in load})
        return load
    loadings = loadings()

print(Foo.loadings)

【讨论】:

  • 非常感谢您的简洁明了的解释!我想向您指出,我的意图是将您最后一个代码块的最后两行替换为 print(Foo.loadings) 之类的内容,并将其用作静态数据成员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-21
  • 2020-09-06
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-09
相关资源
最近更新 更多