質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.59%

pythonの内包表記について

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 1,138

score 104

pythonの内包表記について

リスト内の同様の要素を削除するために以下のサイトを参考に以下の内包表記を実行しました。
https://note.nkmk.me/python-list-unique-duplicate/

def get_unique_list(seq):
    seen = []
    return [x for x in seq if x not in seen and not seen.append(x)]
a = [1,1,1,2,2,3,4,5,6,6,6,7]
print(get_unique_list(a))


結果

[1, 2, 3, 4, 5, 6, 7]


しかし私は以下のコードではないと理解できません。

def get_unique_list1(seq):
    seen = []
    [x for x in seq if x not in seen and seen.append(x)]
    return seen
a = [1,1,1,2,2,3,4,5,6,6,6,7]


結果

[1, 2, 3, 4, 5, 6, 7]

結果は一つ目のコードと二つ目は同じなのですが、
and notを使うかandを使うかという点が違います。
x not in seen and not seen.append(x)の部分を簡単に
A and not Bと置いて考えていくとseenは最初は空の配列なので、
Aは必ず論理を満たします。その後、not seen.append(x)の部分ですが
これはAを満たしたときのみ実行できると考えるとnot seen.append(x)
何もしていないと考えられます。それゆえにseenは空の配列のままです。
それゆえにseenが常に空であればAは必ず論理を満たします。
それゆえに結果は[1,1,1,2,2,3,4,5,6,6,6,7]になるように思えて仕方ありません。
私の考え方のおかしい部分を分かりやすく訂正していただけると幸いです。
よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+4

質問の上の方のコードはseenを捨てて、内包表記の結果を返しています。
質問の下の方のコードは内包表記の結果を捨てて、seenを返しています。

seenというリストと、内包表記の結果のリストの役割が逆なのです。

質問の上の方のコードはifの条件がand not seen.append(x)であることが必須です。内包評価の結果を使うのでこれを逆にするとうまく動きません。

それに対して、質問の下の方のコードはifの条件がand not seen.append(x)でもand seen.append(x)でも動きます。内包表記の結果を捨てているのだからどっちでも動きます。


以下蛇足

seen = []
print(seen.append(1))
print(seen)


結果

None
1

seen = []
print(not seen.append(1))
print(seen)

結果

True
1

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+3

seenは最初は空の配列なので、
Aは必ず論理を満たします。その後、not seen.append(x)の部分ですが
これはAを満たしたときのみ実行できると考える

論理を満たすという言い方はどうかと思いますが(Aが真になるとかでいいのでは)、ここまでは正しい理解でしょう。

not seen.append(x)は何もしていないと考えられます。

Aが「seenにはxが含まれない」であることを忘れているか、not seen.append(x)が「seenにappendしない」という意味と誤解しているかのどちらかだと思います。

notはあくまでも真理値を反転するだけで、後ろの式は評価されます。「含まれていなかったら追加する」「含まれていたら追加しないで終わる」という処理なので、普通に理解できるのでは?

andでつなぐ都合上、seen.append(x)がTrueになってくれないとリスト内包表記の方のifの条件がTrueにならなくて空のリストが返ってしまうので、notで反転しているだけです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/02 15:12

    pythonの言語仕様では、関数・メソッドなどの呼び出しは「式」といって、何らかの値が必ず返ることになっています。余談ですが、他の「式」には変数名とかリテラルとか四則演算など、様々なものがあります。また、「式」の他には「文」があり、ifとかdefとかreturnなどが該当します。「文」は返り値を持たないというか、そもそも代入文の右辺とかリストの中とか、あらゆる「式」が想定される場所には書けないという性質があります。
    話がそれましたが、appendもメソッドで呼び出せば「式」になるので、返り値があります。といっても、appendの返り値なんて要りませんから、Noneというものを返す、という仕様になっています(ちなみにreturn文のない関数を書いてもNoneが返ります)。
    pythonではすべてのオブジェクトはbool型に変換できます。bool(None)はFalseです。なので、これをTrueにするためだけにnotが要るのです。

    キャンセル

  • 2019/03/03 12:18

    理解しました。seen.append(x)の常に返り値がNone(つまり集合の要素がないような集合)にしておくことによってseenにはxを常に加えることができるがnot seen.append(x)をTrueにすることができるということなのですね。非常に分かりやすかったです。ベストアンサーにさせていただきました。

    キャンセル

  • 2019/03/03 12:22 編集

    Noneは別にそこまで深い意味(つまり集合の要素がないような集合)は持ちません。意味がない値というものを表すためにNoneという値が用意されているだけです。

    キャンセル

+3

1番目のコードでは、配列内包をやっている配列の外側にreturnがついています。そして、list.append()Noneを返しますので、それをnotで否定することで、「list.append()を行ったもの」だけがtrueとなります。

Pythonのand短絡評価ですので(リファレンス)、x not in seenが成立しない場合にはnot seen.append(x)は評価されません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/02 13:54

    「これはAを満たしたときのみ実行できると考えるとnot seen.append(x)は何もしていない」という理屈はどのように導かれたものでしょうか。

    キャンセル

  • 2019/03/02 15:06

    根本概念が違っていました。
    私の考えではseen.append(x)はseenにxという配列を加えるもので、真理値を返すという考えがなかったです。
    しかし、list.append()はNoneを返しますという理由が未だに分かりません。もしよかったら、教えて頂けると恐縮です。

    キャンセル

  • 2019/03/02 15:10

    Noneを返すのは、「Python の変更可能なデータ構造全てについての設計上の原則」とのことです。

    https://docs.python.org/ja/3/tutorial/datastructures.html#more-on-lists

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る