web-dev-qa-db-ja.com

リスト内包表記で割り当てを行うにはどうすればよいですか?

リスト内包表記で代入演算子を使用したい。どうやってやるの?

次のコードは無効な構文です。私はlst[0]から空の文字列''patternに一致する場合:

[ lst[0] = '' for pattern in start_pattern if lst[0] == pattern ]

ありがとう!

41
xunzhang

Pythonで list comprehensionlooping constructs を混同しているようです。

リストの内包表記が生成する-リスト!既存のリスト内の単一の割り当てには役立ちません。 (それを行うために構文を拷問することはできますが...)

コードから何をしようとしているかは明確ではありませんが、リストのループ(フロー制御)とリストの生成(リストの理解)に似ていると思います

次のようにリストをループします。

for pattern in patterns:
   if lst[0] == pattern: lst[0]=''

これはこれを行うための合理的な方法であり、C、Pascalなどで行うことです。しかし、1つの値のリストをテストして変更することもできます。

if lst[0] in patterns: lst[0] = ''

または、インデックスがわからない場合:

i=lst.index[pattern]
lst[i]=''

または、リストのリストがあり、各サブリストの各最初の要素を変更する場合:

for i, sublst in enumerate(lst):
    if sublst[i][0] in patterns: sublist[i][0]=''

などなど.

リストの各要素に何かを適用したい場合は、リスト内包表記、マップ、またはPythonキット内の他の多くのツールのいずれかを使用して見ることができます。

個人的には、私は通常、リストの作成のためにリストの内包表記を使用する傾向があります。

 l=[[ x for x in range(5) ] for y in range(4)]  #init a list of lists...

どちらが自然ですか:

l=[]
for i in range(4):
   l.append([])
   for j in range(5):
      l[i].append(j)      

しかし、同じリストのリストを変更するには、どちらがより理解しやすいでしょうか?

この:

l=[['new value' if j==0 else l[i][j] for j in range(len(l[i]))] for i in range(len(l))]

またはこれ:

for i,outter in enumerate(l):
    l[i][0]='new value'               

YMMV

ここ はこれに関する素晴らしいチュートリアルです。

24
dawg

Python言語には、式とステートメントに関する明確な概念があります。

構文は、それを式だと思わせることがある場合でも、割り当てです(例:a=b=99は機能しますが、特別な構文の場合であり、b=99は、たとえばC)のような式です。

リストの内包表記は、値を返すため、代わりに式です。ある意味では、実行するループはインシデントであり、主要なポイントは返されるリストです。

ステートメントには式を含めることができますが、式にステートメントを含めることはできません。

ただし、リストアイテムの割り当ては内部でメソッド呼び出しに変換され(リストのようなオブジェクトの作成を可能にするため)、メソッド呼び出しは式です。したがって、技術的に式でリスト項目の割り当てを使用できます。

[ lst.__setitem__(0, '') for pattern in start_pattern if lst[0] == pattern ]

ただし、これは読みにくいため、ソースコードの読みやすさはPython言語のmain focus)であるため、悪いと見なされます。代わりに例えば...

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''

ちなみに、in演算子のおかげで、さらに読みやすい

if lst[0] in start_pattern:
    lst[0] = ''

リストの内包表記は戻り値に使用され、内部でループを作成します...ループが必要な場合は、ループを作成します...コードの内容を理解しようとする人は誰でも、数週間以内に自分を含めた人)。

9
6502

Python 3.8では、 割り当て式 が導入されます。

これは新しいシンボルです::=は、(とりわけ)内包表記での割り当てを許可します。

それは多くの潜在的な節約w.r.tを紹介します。上記のリンクされたPEPの次のスニペットからわかるように、計算/メモリ(SOに適合したフォーマット):

構文とセマンティクス

任意のPython式を使用できるほとんどのコンテキストでは、名前付き式を表示できます。これはNAME := exprという形式で、exprは括弧なしのタプル以外の有効なPython式であり、NAMEは識別子です。

このような名前付き式の値は、組み込み式と同じですが、ターゲットにその値が割り当てられるという追加の副作用があります。

  1. 一致した正規表現を処理する

    if (match := pattern.search(data)) is not None:
        # Do something with match
    
  2. 2-arg iter()を使用して簡単に書き換えることができないループ

    while chunk := file.read(8192):
        process(chunk)
    
  3. 計算に費用がかかる値を再利用する

    [y := f(x), y**2, y**3]
    
  4. 内包表記フィルター句とその出力の間で部分式を共有する

    filtered_data = [y for x in data if (y := f(x)) is not None]
    

これは、最近リリースされたアルファ版で既に利用可能です(本番システムにはお勧めしません!)。 Python 3.8のリリーススケジュールはこちら にあります。

9
n1k31t4

要するに、あなたはしません。リスト内包表記は、既存のリストを変更するのではなく、リストを生成するためのものです。リストを変更したい場合は、forループを使用してください。

そのコードを記述するPythonの方法は次のようなものになります。

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''
        #the following assumes that pattern will never be ''
        #if that's possible, you can ignore this bit
        break

ただし、本当に本当に本当に1つの内部で割り当てを行い、すべてのPython永遠にそれを嫌うコードを扱うプログラマーを気にしないでください。使用する:

  • 割り当てる変数がグローバルである場合、次のことができます

        globals().update(var=value)
    
  • 割り当てる変数が可変シーケンスまたはマップ(リストや辞書など)である場合

        list.__setitem__(index, value)
    
6
Colin Valliant

質問の内容が次の場合:

[ lst[0] = '' for lst in listOfLists if lst[0] == pattern ]

またはパターンのリスト

[ lst[0] = '' for lst in listOfLists if lst[0] in patterns ]

これは実際に簡単に行うことができます

[ [''] + lst[1:] for lst in listOfLists if lst[0] == pattern ]

または再びパターンのリストのために

[[''] + lst[1:] for lst in listOfLists if lst[0] in patterns ]
0
Jamie Marshall