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

时间:2012-07-31 21:59:12

标签: 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))

这会产生NameError: global name 'first_d' is not defined

我该怎样做这个参考?这种模式似乎适用于其他情况,例如:

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

3 个答案:

答案 0 :(得分:5)

基本列表理解具有以下syntax

[expression for var in iterable]

当一个类内部发生列表解析时,该类的属性 可以在iterable中使用。在Python2和Python3中也是如此。

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

生成器表达式的故事有点不同:

(expression for var in iterable)

虽然仍可以从iterable访问类属性,但无法从expression访问类属性。 (这适用于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))

发生NameError因为first_d无法从生成器表达式的expression部分访问。

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)}

因为它在first_d而不是词典理解的iterable部分使用expression。但是如果first_d包含许多项目,这可能会循环通过不必要的项目。 Neverthess,如果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理解中访问此局部范围中的变量。

这是explained here,但我对此并不十分满意,因为它没有解释为什么expression部分的行为与列表理解,生成器表达式的iterable部分或dict理解。

因此,我无法解释(完全)为什么 Python以这种方式运行,只是这就是它的行为方式。

答案 1 :(得分: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}

答案 2 :(得分:0)

我不认为这个类存在,直到你的定义结束。