基本列表推导具有以下语法
[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
(在这方面,字典推导的行为与生成器表达式相同。)
现在这与您的问题有什么关系:
在你的例子中,
second_d = dict((k,first_d[k]) for k in (2,3))
aNameError
发生是因为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
但是,如果包含许多项目,这可能会遍历比必要更多的项目。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 理解中访问该局部范围内的变量。
这在此处进行了解释,但我对此并不完全满意,因为它没有解释为什么该expression
部分的行为与iterable
列表理解、生成器表达式或 dict 理解的部分不同。
因此,我无法(完全)解释为什么Python 会以这种方式行事,只能说这是它看起来的行为方式。