基本的なリスト内包表記には次の構文があります
[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))
aは、ジェネレーター式の一部からアクセスできない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
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]
関数はローカル スコープを定義し、このローカル スコープ内の変数に辞書内包表記内からアクセスできるため、機能します。
これはhere で説明されましたが、リスト内包表記、ジェネレーター式、または dict 内包表記expression
の部分とは異なる動作をする理由が説明されていないため、私はこれに完全に満足しているとは言えません。iterable
したがって、 Python がこのように振る舞う理由を (完全に) 説明することはできません。