:=
Python 3.8で追加された代入式演算子は、ラムダ式内での代入をサポートしています。この演算子は、構文上の理由から、括弧(...)
、括弧[...]
、または括弧で囲まれた{...}
式内にのみ出現できます。たとえば、次のように記述できます。
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Python 2では、リスト内包の副作用としてローカル割り当てを実行することが可能でした。
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
ただし、変数flag
がのスコープではなく外部スコープにあるため、これらの例のいずれかを使用することはできませんlambda
。これはとは関係ありませんlambda
。Python2の一般的な動作です。Python3ではnonlocal
、def
sの内部でキーワードを使用してこれを回避できますが、内部ではnonlocal
使用できません。lambda
。
回避策があります(下記を参照)が、このトピックについては...
場合によっては、これを使用して内ですべてを実行できますlambda
。
(lambda: [
['def'
for sys in [__import__('sys')]
for math in [__import__('math')]
for sub in [lambda *vals: None]
for fun in [lambda *vals: vals[-1]]
for echo in [lambda *vals: sub(
sys.stdout.write(u" ".join(map(unicode, vals)) + u"\n"))]
for Cylinder in [type('Cylinder', (object,), dict(
__init__ = lambda self, radius, height: sub(
setattr(self, 'radius', radius),
setattr(self, 'height', height)),
volume = property(lambda self: fun(
['def' for top_area in [math.pi * self.radius ** 2]],
self.height * top_area))))]
for main in [lambda: sub(
['loop' for factor in [1, 2, 3] if sub(
['def'
for my_radius, my_height in [[10 * factor, 20 * factor]]
for my_cylinder in [Cylinder(my_radius, my_height)]],
echo(u"A cylinder with a radius of %.1fcm and a height "
u"of %.1fcm has a volume of %.1fcm³."
% (my_radius, my_height, my_cylinder.volume)))])]],
main()])()
半径10.0cm、高さ20.0cmの円柱の体積は6283.2cm³です。
半径20.0cm、高さ40.0cmの円柱の体積は50265.5cm³です。
半径30.0cm、高さ60.0cmの円柱の体積は169646.0cm³です。
しないでください。
...元の例に戻ります。flag
外側のスコープで変数への割り当てを実行することはできませんが、関数を使用して、以前に割り当てられた値を変更できます。
たとえば、次のflag
よう.value
に設定したオブジェクトを使用できますsetattr
。
flag = Object(value=True)
input = [Object(name=''), Object(name='fake_name'), Object(name='')]
output = filter(lambda o: [
flag.value or bool(o.name),
setattr(flag, 'value', flag.value and bool(o.name))
][0], input)
[Object(name=''), Object(name='fake_name')]
上記のテーマに適合させたい場合は、setattr
次の代わりにリスト内包表記を使用できます。
[None for flag.value in [bool(o.name)]]
しかし、実際には、深刻なコードでは、lambda
外部代入を行う場合は、代わりに常に通常の関数定義を使用する必要があります。
flag = Object(value=True)
def not_empty_except_first(o):
result = flag.value or bool(o.name)
flag.value = flag.value and bool(o.name)
return result
input = [Object(name=""), Object(name="fake_name"), Object(name="")]
output = filter(not_empty_except_first, input)