文字列の挿入を多用する場合のパフォーマンスについて

モジュロ演算は便利だが

from timeit import Timer
ins = 'ins'
def through():
    return ins
def modulo1():
    return """%s""" % ins
def modulo2():
    return """%s0123456789""" % ins
def modulo3():
    return """0123456789%s""" % ins

print Timer('through()', 'from __main__ import through').timeit(100000)
print Timer('modulo1()', 'from __main__ import modulo1').timeit(100000)
print Timer('modulo2()', 'from __main__ import modulo2').timeit(100000)
print Timer('modulo3()', 'from __main__ import modulo3').timeit(100000)

win
0.022329374264
0.0360696680723
0.0411538337973
0.0406523734162
linux
0.0284080505371
0.0974290370941
0.0858700275421
0.0761489868164


多少のロスはある
あとlinuxでコストが高いみたい


また、長い文字列では

#1. 長い文字列でもそのままモジュロ
def modulo():
    return (
        """01234567890123456789%s"""
        """01234567890123456789%s"""
        % (ins, ins)
        )
#2. (モジュロの走査コストを下げるという意味で)分割してjoin
def join1():
    return ''.join([
        """01234567890123456789%s""" % ins,
        """01234567890123456789%s""" % ins
        ])
#3. モジュロをつかわずjoin
def join2():
    return ''.join([
        """01234567890123456789""",
        ins,
        """01234567890123456789""",
        ins
        ])

print Timer('modulo()', 'from __main__ import modulo').timeit(100000)
print Timer('join1()', 'from __main__ import join1').timeit(100000)
print Timer('join2()', 'from __main__ import join2').timeit(100000)

win
0.066571868771
0.128980359236
0.0771374574143
lin
0.127910852432
0.201925039291
0.111853837967


ある程度の量になるとパフォーマンスは3、1、2の順で良い
win
x4

def modulo():
    return (
        """01234567890123456789%s"""
        """01234567890123456789%s"""
        """01234567890123456789%s""" #ここから
        """01234567890123456789%s""" 
        """01234567890123456789%s""" 
        """01234567890123456789%s""" 
        """01234567890123456789%s""" 
        """01234567890123456789%s""" #ここまで増えた
#以下略

0.210147658431
0.311319734771
0.128293400418
x2
0.318634351573
0.58512464573
0.217619837158
x2
0.557505213651
1.07723132409
0.357247918381


linux
x4
0.288574934006
0.566724061966
0.247048139572
x2
0.456442832947
1.03662586212
0.384277105331
x2
0.852335214615
1.98628687859
0.755924940109


1だと文字列が長くなったときに管理が難しくなるので

title = 'hoge'
''.join([
    """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n"""
        """<html>\n"""
        """<head>\n"""
            """<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n"""
            """<title>""",
               title,
            """</title>\n"""
            """<link rel="stylesheet" type="text/css" href="hoge.css">\n"""
            """<script type="text/javascript" src="http://www.google.com/jsapi"></script>\n"""
            """<script type="text/javascript">google.load("jquery", "1.2.6");</script>\n"""
        """</head>\n"""
        """<body>\n"""
            """<div id="hoge">"""
    ])

のような感じでやるのが早くて間違えにくい

    """<a href="%s">link</a>""" % url

とかだと分割すると見づらくなるのでモジュロでいい気もする

短い文字列は単なるモジュロ、
長い文字列は2と3を併用がベストかな


ちなみに上の例の

''.join([
    """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n"""
        """<html>\n"""
        """<head>\n"""

みたいな書き方、pythonのインデントに従いつつHTML的にもわかりやすいので気に入ってるんだがperl使いの人にはきめえwといわれた
そうなんだろうなあ
数年後には自分の中でもたぶんそんな扱いになってる気がする