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の最後の良心と言えるかも知れない。