2017-07-14 6 views
2

私はまだPythonには新しく、元のリストとリストの両方のリストを逆にする小さな関数を作っています。これは私のコードです:Python:リストの値をインラインに割り当てると、 "None"要素のリストが返されるのはなぜですか?

def deep_reverse(L): 
    L.reverse() 
    L = [i.reverse() for i in L] 

今、このコードは完璧に動作しますが、私は小さな変更を行うと、このような行を並べ替える場合:

def deep_reverse(L): 
    L = [i.reverse() for i in L] 
    L.reverse() 

を突然、それは動作を停止します!内部リストのみを元に戻しますが、元のリストは元に戻しません。一部のデバッグprint()ステートメントを内部に置くと、最初のコードが最初の行の後に元のリストを反転して印刷されているのが見えますが、2番目のコードは実際にはリストを反転した後に要素として 'None'を含むリストを出力します。誰もがなぜこの動作と2つのコードの違いは何かを説明してくださいできますか?

+2

あなたはリスト内包表記を誤解しています。 'L 'に代入すると、関数に渡されたものは変更されず、' reverse() 'は何も返しません。 'for i in L:i.reverse()'でなければなりません。 – Ryan

+0

しかし、コードは動作します。それがうまくいくなら私はそれをどうやって悪用しますか? –

+0

両方の機能の最後に 'return L 'を忘れた場合 –

答えて

1

関数reverse()は、リストをその場で逆にして、奇妙な動作を説明するNoneを返します。正しい実装は次のようになります。

def deep_reverse(L): 
    ans = [i[::-1] for i in L] 
    ans.reverse() 
    return ans 

また、それが再割り当ておよび/または機能にパラメータを変異させ、それは予期しない結果につながることができますし、悪い考えです。時には、標準ライブラリの関数が効率の理由から(例えば、sort()reverse())、それは問題ありませんが、経験したような混乱を招く可能性があります。厳密に必要な場合を除いて、あなたのコードをそのように書く必要はありません。

+0

または 'reversed(i)'は、スライシング方法よりも読みやすくなる可能性があります – swalladge

+0

ありがとうございます! –

+0

@swalladgeしかし、_iterators _...のリストを生成します。 –

1

最初のdeep_reverseファンクションはLに再割り当てされましたが、グローバルパラメータではなく、関数には返されません。したがって、この変数は失われます。しかし、あなたはその場でリストを突然変異させているので、変更が残っているので、それはまだ動作します!あなたの本来の機能が(何の最終割り当てがありません注意してください)以下と等価です:

def deep_reverse(L): 
    L.reverse() 
    [i.reverse() for i in L] 

これはおそらくforループ使用して記述する必要があります:

def deep_reverse_2(L): 
    L.reverse() 
    for i in L: 
     i.reverse() 

L = [[1, 2, 3], [2, 3, 4]] 
deep_reverse_2(L) 
>>> L 
[[4, 3, 2], [3, 2, 1]] 

第二の機能はあなたのために動作しません。関数内にLを再割り当てします(関数にローカルであり、関数に渡された変数と同じLではありません)。 idを使用してチェックした場合、メモリの場所が異なります。何も返されないと仮定すると、この新しいLのリストは失われ、その変更も失われます。

+0

ありがとう。しかし、私が説明したように、コードは外側のリストと内側のリストの両方を逆転させたい。あなたのコードは内側の要素だけを逆転させます。編集:実際に私の最初のdeep_reverse()関数は動作し、2番目の問題は私が持っていたものです。 –

+0

編集が正しくありません。上記を訂正。 – Alexander

+0

ありがとうございます。上記の私の編集したコメントも読んでください。 –

関連する問題