2011/2/11 追記 たくさんコメントを頂きました

見易いようにコードを引用します。

def limit_characters_by_ishimoto(s, start, maximum, end=None):
    return [s[f:f+maximum] for f in range(start, (end if end else len(s)), maximum)]

range() だけで開始位置の計算はできました。 range() の step は知ってはいたけど、思いつかなかったです。こういう突っ込みをもらうことで1つ応用例が学べて良かったです。

もう1つ、コメントにもあるように @ からジェネレータ一発でやってみましたとあります。

書いてみた - cocoatomo衝動日記

この実装を見ていていくつか気付きました。私のコードの中で、

    from math import ceil
    div_num = int(ceil(len(_s) / float(maximum)))

と、例えば 1.2 だったら 2 といったように切り上げしたいがためにやや煩雑なことをしていますが、

def my_ceil(n1, n2):
    """
    >>> my_ceil(0, 1)
    0
    >>> my_ceil(1, 1)
    1
    >>> my_ceil(2, 5)
    1
    >>> my_ceil(5, 3)
    2
    >>> my_ceil(8, 3)
    3
    """
    return ((n1 - 1) / n2) + 1

でも同じことができますね。あと、私の書いたコードはジェネレータを for 文でぐるぐるまわしてますが、組み込み関数の list() にジェネレータを渡すとリストを返してくれることにも気付きました。他の人の実装を読むのは勉強になります。

def generator(num):
    """
    >>> list(generator(5))
    [0, 1, 2, 3, 4]
    """
    return (i for i in xrange(num))

同じ環境でプロファイルを取ってみました。

In [3]: timeit -n 3 limit_characters_by_ishimoto(s, 0, 80)
3 loops, best of 3: 21.1 us per loop

In [4]: timeit -n 3 list(limit_characters_by_cocoatomo(s, 0, 80))
3 loops, best of 3: 77.3 us per loop

@ の実装はループ処理がさらに効率化されて2倍速くなっていますね。

結論をまとめます。

最後に言いたいことは textwrap は覚えとこう - methaneのブログ です。

追記、終わり。


以下、簡単なテストコードです。興味のある方はどうぞ。

def test_limit_characters_null():
    test_line = ""
    assert [] == limit_characters1(test_line, 0, 2)
    assert [""] == limit_characters2(test_line, 0, 2)
    assert [""] == limit_characters3(test_line, 0, 2)

def test_limit_characters_max():
    test_line = "12345"
    result = {
        1: ["1", "2", "3", "4", "5"],
        2: ["12", "34", "5"],
        3: ["123", "45"],
        4: ["1234", "5"],
        5: ["12345"],
        6: ["12345"],
    }
    for i in xrange(1, 6):
        r = result[i]
        assert r == limit_characters1(test_line, 0, i)
        assert r == limit_characters2(test_line, 0, i)
        assert r == limit_characters3(test_line, 0, i)

def main():
    test_limit_characters_null()
    test_limit_characters_max()

if __name__ == "__main__":
    main()