読者です 読者をやめる 読者になる 読者になる

Python3.0で話すように素数

Python

Scalaで話すように素数 - なんたらノート 第二期
のついでに、まだ使い物にならないけど、一応Python3.0の場合を書いときます。

続・話すようにプログラムするPythonチュートリアル - なんたらノート 第二期
と比べてどうでしょう?

from decorator import *

@decorator
def memoize(func, *args):
    if not hasattr(func, "memoize_dic"):
        setattr(func, "memoize_dic", dict())
    dic = getattr(func, "memoize_dic")
    if args in dic:
        return dic[args]
    else:
        result = func(*args)
        dic[args] = result
        return result

@memoize
def is_prime_number(n):
    return not any(map(lambda m: n % m == 0, prime_numbers_until(n-1)))

def prime_numbers_until(limit):
    return filter(is_prime_number, range(2, limit))

print(list(prime_numbers_until(100)))

itertools.ifilterはfilterに、itertools.imapはmapに、というように、itertoolsの一部がビルトイン関数に格上げされ、listのコピーを取っていたビルトイン関数はお役御免になりました。dictのkeysやitemsも、リストを直接返さず、イテレータを返してくれます。rangeも同様に、これまでのxrangeはrangeとなり、いきなり大きなリストを返すあの重いrangeもなくなりました。
これで、なにも気にせず書いたプログラムでも、プログラムの量とデータの量が自然な計算負荷になりますね。

ただし、リスト内包は「リストリテラルの一種」という解釈になるらしく、いきなり大きなリストを作ってしまいます。「map+filterとリスト内包は同じものの別の記法」ではなくなりました。これはちょっとした罠かも。

[n for n in range(10)]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
map(lambda n: n, range(10))
# <map object at 0x00BBBED0>

追記
Python3.0のmap/filterは、Python2.5で登場したジェネレータ式と同じものになったと考えるのが自然だと気づきました。マイナーな構文ですが、ジェネレータ式とは、リスト内包式の結果がリストではなくイテレータになったものです。

(n for n in range(10))
# <generator object at 0x02019508>
map(lambda n: n, range(10))
# <map object at 0x0209C198>
注意:ここで使っているdecoratorパッケージは独自に修正したものです

これ書いてる段階の最新版、decorator-2.3.2に含まれるdecorator.pyは、新しい関数オブジェクトの仕様にあわせて修正しないといけません。easy_installもまだないので、decoratorのソースにあるsetup.pyでインストールしなきゃいけないです。

decorator.py パッチ

57c57
<                 defaults = func.func_defaults, doc=func.__doc__,
---
>                 defaults = func.__defaults__, doc=func.__doc__,
59c59
<                 globals=func.func_globals, closure=func.func_closure)
---
>                 globals=func.__globals__, closure=func.__closure__)
71c71
<     wrapper.func_defaults = infodict['defaults']
---
>     wrapper.__defaults__ = infodict['defaults']