![](/img/trans.png)
[英]Why is one class variable not defined in list comprehension but another is?
[英]Reference class variable in a comprehension of another class variable
这可能是一个简单的问题,但我无法进行独特的搜索。
我有一个定义静态字典的类,然后尝试静态地定义该字典的子集。
所以,作为玩具的例子:
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
基本列表推导具有以下语法
[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
是因为无法从生成器表达式的expression
部分访问first_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理解的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]
函数起作用是因为它们定义了局部范围,并且可以从字典理解中访问此局部范围中的变量。
这里解释了这一点,但我对此并不完全满意,因为它没有解释为什么expression
部分的行为与列表理解,生成器表达式或字典理解的iterable
部分的行为不同。
因此,我无法(完全)解释为什么 Python会以这种方式运行,只是这就是它的行为方式。
它有点kludgy,但你可以试试这个:
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}
我不认为这个类存在,直到你的定义结束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.