このサイトについて

「逆に凄いわ」って感心するPythonのlambda活用法

「逆に凄いわ」って感心するPythonのlambda活用法

Pythonのlambdaは無名関数を式で作ることができる文法。なんか関数言語っぽくて,「LISPの正当な継承者はPythonだ」という気にさせるクールな機能。

クールだけど,使い方を間違えると大変なことになる。乱用は避けたい。極端すぎるほどアナーキーなlambdaの使い方を見つけたので,反面教師としていくつかの例を紹介します。なお,このコードはあまりにアナーキーなのでPython 3.xでは(一部)動きません。

def pow(x, power):
    return x**power

というコードがあったとして,

pow = lambda x, power: x**power

みたいにlambdaを使うのはまあいい。

import random, string
characters = string.digits + string.letters

def randomPasswordGenerator(length):
    return ''.join(random.choice(characters) for i in xrange(length))

こんな風にモジュールをインポートしたり変数を定義したりして,スコープが絡んでくるともう大変になる。しょうがないのでlambaを入れ子にすることになる。

randomPasswordGenerator = \
(lambda random, string: # level 1
    (lambda characters: # level 2
        lambda length: ''.join(random.choice(characters) for i in xrange(length)) # level 3
    )(string.digits + string.letters) # level 2 args
)(
    __import__('random'), # level 1 args
    __import__('string')
)

ふう。

lambaで作った関数は「無名関数」と呼ばれており,関数オブジェクトが持つ関数名(__name__)が定義されない。

>>> def foo(): pass;  # 関数を定義
...
>>> foo.__name__    # __name__アトリビュートを表示
'foo'
>>> bar = lambda x: x   # lambdaを使って関数を作る
>>> bar.__name__    # __name__アトリビュートがヘンだ...
'<lambda>'

lambdaで定義した関数にむりやり関数名を定義しようとすると大変なことになる。

myFunc = (lambda(new):
    new.function(
        (lambda a, b: a + b).func_code, {}, 'myFunc'
    )
)(__import__('new'))

lambdaのすばらしさが分かってきただろうか。盛り上がってきたところで,lambdaでクラスを定義してみよう。え? 「出来るはずない?」って? lambaに不可能はないのだ。

Foo = (lambda(new): # level 1, we define our new variable.
        new.classobj('Foo', (), dict( # return a class object.
            classVariable = 'ImAClassVariable',
            __init__ = (lambda self, a, b, c:
                self.__dict__.update(dict(
                    _a = a,
                    _b = b,
                    _c = c
                ))
            ),
            getA = lambda self: self._a,
            aClassMethod = classmethod(
                lambda cls: cls.classVariable
            ),
            aStaticMethod = staticmethod(
                lambda a, b: a + b
            ),
            __repr__ = (lambda self:
                '<%s: %r>' % (
                    self.__class__.__name__,
                    vars(self)
                )
            )
        ))
    )(__import__('new')) # level 1 args

classmethodやstaticmethodも定義されているところに注目。lambdaスゲー。

lambaを使えば,クールなマイクロフレームワークももっとクールに!

from flask import Flask

app = Flask('__name__')

@app.route('/')
def index():
    return 'Hello World!'

app.run()

# ...

(lambda flask:
    (lambda app:
        (app,
         app.route('/')(
            lambda: 'Hello World!'
         )
        )[0]
    )(flask.Flask('__name__')).run()
)(__import__('flask'))

最後に注記しておくと,lambaを使ったコードはすべてワンライナーで書ける。分かりやすく改行とインデントしてあるのは,Pythonistaの最後の良心と言えるかも知れない。

2011-06-14 01:10