81

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

次のコードは無効な構文です。一致する場合lst[0]は空の文字列に設定することを意味します:''pattern

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

ありがとう!

4

8 に答える 8

37

リスト内包表記とPython のループ構造を混同しているようです。

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

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

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

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 キットの他の多くのツールの 1 つを使用して調べることができます。

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

 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

これに関する素晴らしいチュートリアルがあります

于 2012-04-24T05:11:56.670 に答える
13

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

代入は、構文が式であると思わせる場合がありますが、ステートメントです (たとえば、機能しますが、特殊な構文のケースであり、たとえば C のような式であるa=b=99とは限りません)。b=99

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

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

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

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

ただし、これは可読性を損ない、Python 言語ではソース コードの読みやすさが主な焦点であるため、悪いと考えられています。たとえば、代わりに書く必要があります...

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

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

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

リスト内包表記は戻り値に使用され、内部でループを作成します...ループが必要な場合は、ループを記述してください...コードが何をするかを理解しようとしてコードを読む人は誰でも、それを高く評価します(そして数週間であなた自身を含む人は誰でも)。

于 2012-04-24T06:20:03.977 に答える
9

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

そのコードを書く Pythonic の方法は次のようになります。

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)
    
于 2012-04-24T05:14:37.163 に答える
1

上記の回答で述べたように、リスト内包表記機能では直接代入はできませんがexec、代入を達成する方法を使用してそれを行うハッキング可能な方法があります。

assignmentsPython 式をexecメソッドに渡して評価できるだけではありません。

あなたの場合、それは

  [ exec(f"lst[0] = ''") for pattern in start_pattern if lst[0] == pattern ]

オブジェクトのリストがあり、特定の条件でオブジェクトの特定の属性に値を割り当てたい場合は、次のようになります。

[ exec("p.age_status=child") for p in persons_obj_list if p.age <= 18 ]

注: これは、リストの既存のオブジェクトの状態を変更し、リスト内包表記の通常の使用で返されるように、オブジェクトのリストを返しません。

于 2020-12-31T15:50:51.070 に答える
0

質問であなたが述べていることが次の場合:

[ 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 ]
于 2018-07-31T01:08:23.207 に答える