Python 在理解另一个类变量时引用类变量

Python 在理解另一个类变量时引用类变量,python,dictionary,class-variables,Python,Dictionary,Class Variables,这可能是一个简单的问题,但我在进行独特的搜索时遇到了困难 我有一个类,它定义了一个静态字典,然后试图定义该字典的一个子集,也是静态的 因此,作为一个玩具示例: class example(object): first_d = {1:1,2:2,3:3,4:4} second_d = dict((k,first_d[k]) for k in (2,3)) 这将产生name错误:未定义全局名称“first\u d” 我应该如何做这个参考?似乎这种模式在其他情况下也适用,例如:

这可能是一个简单的问题,但我在进行独特的搜索时遇到了困难

我有一个类,它定义了一个静态字典,然后试图定义该字典的一个子集,也是静态的

因此,作为一个玩具示例:

class example(object): 
    first_d = {1:1,2:2,3:3,4:4} 
    second_d = dict((k,first_d[k]) for k in (2,3))
这将产生
name错误:未定义全局名称“first\u d”

我应该如何做这个参考?似乎这种模式在其他情况下也适用,例如:

class example2(object):
    first = 1
    second = first + 1

这有点麻烦,但你可以试试这个:

class test(object):
    pass

test.first = {1:1, 2:2, 3:3, 4:4}
test.second = dict((k, test.first[k]) for k in (2,3))
…然后:

>>> test.first
{1: 1, 2: 2, 3: 3, 4: 4}
>>> test.second
{2: 2, 3: 3}

>>> t = test()
>>> t.first
{1: 1, 2: 2, 3: 3, 4: 4}
>>> t.second
{2: 2, 3: 3}

>>> test.first[5] = 5
>>> t.first
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5}

我认为这个类在定义结束之前是不存在的。

基本列表理解有以下几点

当列表理解发生在类内部时,类的属性 可在
iterable
中使用。这在Python2和Python3中是正确的

但是,类的属性可以在Python2的
表达式中使用(即访问),但不能在Python3中使用

生成器表达式的情况有点不同:

(expression for var in iterable)
虽然仍然可以从
iterable
访问类属性,但不能从
表达式
访问类属性。(这对于Python2和Python3是正确的)

这一切可以概括如下:

                             Python2      Python3
Can access class attributes
--------------------------------------------------
list comp. iterable                Y            Y
list comp. expression              Y            N
gen expr. iterable                 Y            Y
gen expr. expression               N            N
dict comp. iterable                Y            Y
dict comp. expression              N            N
(在这方面,Dict理解与生成器表达式的行为相同。)


现在这与您的问题有什么关系:

以你为例,

second_d = dict((k,first_d[k]) for k in (2,3))
发生
名称错误
,因为无法从生成器表达式的
部分访问
first\u d

Python2的一个解决方法是将生成器表达式更改为列表:

second_d = dict([(k,first_d[k]) for k in (2,3)])
然而,我觉得这不是一个非常舒适的解决方案,因为这段代码在Python3中会失败

你可以按照Joel Cornett的建议:

second_d = {k: v for k, v in first_d.items() if k in (2, 3)}
因为这使用的是
iterable
中的
first\d
,而不是dict理解的
表达式部分。但是,如果
first\d
包含许多项,则这可能会循环通过比需要更多的项。尽管如此,如果
first\d
很小,这个解决方案可能很好

通常,您可以通过定义可在类内部或外部定义的帮助器函数来避免此问题:

def partial_dict(dct, keys):
    return {k:dct[k] for k in keys}

class Example(object):
    first_d = {1:1,2:2,3:3,4:4}
    second_d = partial_dict(first_d, (2,3))

class Example2(object):
    a = [1,2,3,4,5]
    b = [2,4]
    def myfunc(A, B):
        return [x for x in A if x not in B]
    c = myfunc(a, b)

print(Example().second_d)
# {2: 2, 3: 3}

print(Example2().c)
# [1, 3, 5]
函数之所以起作用,是因为它们定义了本地范围和 此局部范围内的变量可以从dict理解中访问

这是,但我对此并不完全满意,因为它没有解释为什么
表达式
部分的行为不同于列表理解、生成器表达式或dict理解的
iterable
部分


因此,我不能(完全)解释Python为什么会这样做,只是它看起来是这样的。

这不是一个“静态”字典。为什么这些不能是实例变量呢?嗯,奇怪的是,这很好:
second_d={k:v代表k,v在first_d.items()如果k在(2,3)}
@ColinDunklau:我在尝试模拟一个枚举,我想是吧。我正在为第三方程序编写一个控制器,为此我将汇编一个控制参数的文本文件。这些都是模块化的,基本上是固定的。我的控制器每次只能运行其中的一个子集。所以我希望每个控制器都有一个实例变量,定义为定义所有可能集合的字典的子集。此处的
第二个\u d
是默认集,而不是最终集。如果这不是最好的做事方式,我很乐意考虑其他事情。请你把它作为一个答案,这样我就可以接受了,好吗?你知道为什么它不起作用吗,因为它确实起作用:
second\u d={k:v代表k,v在first\u d.items()中,如果k在(2,3)}
?谢谢你的精彩答案。对于试图使用列表理解/iterable来初始化静态变量的人(在python 3中),这是一个潜在的解决方案:如上所述将理解/iterable定义为一个函数(并用
@staticmethod
标记它),例如
myfunc(params)
,然后使用
myfunc.\ufunc\uu(params)
调用它。实际上,我将编辑答案以包含一个示例。
def partial_dict(dct, keys):
    return {k:dct[k] for k in keys}

class Example(object):
    first_d = {1:1,2:2,3:3,4:4}
    second_d = partial_dict(first_d, (2,3))

class Example2(object):
    a = [1,2,3,4,5]
    b = [2,4]
    def myfunc(A, B):
        return [x for x in A if x not in B]
    c = myfunc(a, b)

print(Example().second_d)
# {2: 2, 3: 3}

print(Example2().c)
# [1, 3, 5]