続・リスト内包表記

  • Python文法詳解買っちゃった

Amazon.co.jp: Python文法詳解: 石本 敦夫: 本
 python文法詳解発売されたので早速買ってみました。p.81の4.2.2のリスト内包の欄にて、次のような記述を見つけたのでメモ。こんなこともできたんですね。

>>> L = [(1,'a'),(2,'b'),(3,'c')]
>>> [c*i for i,c in L]
['a', 'bb', 'ccc']
>>> L = [(1,2),(3,4,5),(6,7,8,9)]
>>> [car*sum(cdr) for car,*cdr in L]
[2, 27, 144]

car, cdrという変数名になっているのはLispっぽいですね。*を付けることで残りのシーケンスを指すポインタ(?)として機能しています。
ちょっとLispで書いてみましょう。schemeの教科書なら一番初めに載ってる例です。

#lang racket
> (car '(1 2 3 4))
1
> (cdr '(1 2 3 4))
'(2 3 4)

(最近はracketでschemeも勉強しています。racketもとい、scheme, Lispに興味がある人は、こちらのURLへどうぞ)


The Racket Language

いつ通りの書き方も載せておきましょう。添字(そえじ)が見やすい人はこちらでどうぞ。

>>> L = [(1,'a'),(2,'b'),(3,'c')]
>>> [t[0]*t[1] for t in L]
['a', 'bb', 'ccc']
>>> L = [(1,2),(3,4,5),(6,7,8,9)]
>>> [t[0]*sum(t[1:]) for t in L]
[2, 27, 144]
  • 何か違いはあるの?

(car,cdr)型と添字型。この二つの表記は全く同じ結果を出力するのでしょうか?どうやら、少しだけ違いがあるようです。

>>> L = [(1,2),(3,4,5),(6,7,8,9)]
>>> [t[0]*t[1:] for t in L]
[(2,), (4, 5, 4, 5, 4, 5), (7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9)]
>>> [car*cdr for car,*cdr in L]
[[2], [4, 5, 4, 5, 4, 5], [7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9, 7, 8, 9]]

今度は、本に載っていた例を勝手に書き換えた、というかsum()を抜いた例です。よく見ると、片方はtuple型ですが、もう片方はlist型です。(そもそも、掛け算とポインタが入り混じった内包表記はよろしくないかもしれませんが。)なぜこうなるのかというと、

>>> a,*b = (1,2,3)
>>> a
1
>>> b
[2, 3]

こうなってるんでした。つまり、タプル(tuple)はこの(car,cdr)型にした途端にリスト(list)へと形を変えていたんですね。