リスト内包表記について

いまさらリスト内包表記かよって言われそうだけど、まぁなんどおさらいしたっていいじゃない。という訳で下記のような事がやりたいとする。

  • カンマ区切りの数字の列を文字列として受け取る(50,100,150,200,250)
  • その文字列をカンマで分割してリストにする
  • リストの各要素をint型にキャストする
  • 最終的にリストをtuple型にキャストする
''50,100,150,200,250"
              ↓変換
(50, 100, 150, 200, 250)

1. ベタにやってみる。

ベタな感じやってみるとこうなる

#!/usr/bin/env python
#-*- coding:utf8 -*-

num_str = '50,100,150,200,250'
num_list = []
for n in num_str.split(','):
    num_list.append(int(n))
print tuple(num_list) #=> (50, 100, 150, 200, 250)

実行結果

2. リスト内包表記でやってみる。

上のでも大した行数ではないけど、リスト内包表記を使う事でより簡潔にかける!

#!/usr/bin/env python
#-*- coding:utf8 -*-

num_str = '50,100,150,200,250'
print  tuple([int(n) for n in num_str.split(',')]) #=> (50, 100, 150, 200, 250)

実行結果

3. リスト内包表記の方がパフォーマンスが良い。

エキスパートPythonとか、初めてのPython(オライリー本)にも書いてあったけど、リスト内包表記の方が、往々にしてパフォーマンスが良いとされている。実際に上の二つを比較してみる。

こういう小さいコードの計測する時にはtimeitというモジュールを使うといいらしい。

#!/usr/bin/env python
#-*- coding:utf8 -*-
import timeit

setup = """
num_str = '50,100,150,200,250'
def num_str_to_tuple(): 
    num_list = []
    for n in num_str.split(','):
        num_list.append(int(n))
    return tuple(num_list)
""" 
stmt = "num_str_to_tuple()"
t = timeit.Timer(stmt=stmt, setup=setup)
print t.timeit(2000000)

setup = """
num_str = '50,100,150,200,250'
def num_str_to_tuple(): 
     return tuple([int(n) for n in num_str.split(',')])
"""
stmt = "num_str_to_tuple()"
t = timeit.Timer(stmt=stmt, setup=setup)
print t.timeit(2000000)

リスト内包表記のパフォーマンスがいいからといって今回の例だと、あまりに例がシンプルすぎて差がわかりずらいので、あえて実行回数を多めにしている。

手元の環境で上記計測コードを実行すると。こんな感じ

14.5897488594 #リスト内包表記を使ってない
13.1452250481 #リスト内包表記を使ってる

200まんかいずつ繰り返したら一秒くらいはやくなりますた。

追記(20110916)

よく考えたら、上の計測のヤツは、num_str のカンマで区切られた要素数が、多いほど、差が顕著にでるような気がしたので下記のようにしてみた。

#!/usr/bin/env python
#-*- coding:utf8 -*-
import timeit

setup = """
num_str = ','.join([str(i) for i in range(10000000)])
def num_str_to_tuple(): 
    num_list = []
    for n in num_str.split(','):
        num_list.append(int(n))
    return tuple(num_list)
"""
stmt = "num_str_to_tuple()"
t = timeit.Timer(stmt=stmt, setup=setup)
print t.timeit(1)

setup = """
num_str = ','.join([str(i) for i in range(10000000)])
def num_str_to_tuple(): 
     return tuple([int(n) for n in num_str.split(',')])
"""
stmt = "num_str_to_tuple()"
t = timeit.Timer(stmt=stmt, setup=setup)
print t.timeit(1)

結果はこんな感じ

12.9693031311 #リスト内包表記を使ってない
11.8190917969 #リスト内包表記を使ってる

あんま上の計測のヤツと変わりませんでした。。。

参考

初めてのPython 第3版

初めてのPython 第3版

エキスパートPythonプログラミング

エキスパートPythonプログラミング