Pythonのラムダ式内での代入 質問する

Pythonのラムダ式内での代入 質問する

オブジェクトのリストがあり、式を使用して、1 つを除く空のオブジェクトをすべて削除したいと考えていfilterますlambda

たとえば、入力が次の場合:

[Object(name=""), Object(name="fake_name"), Object(name="")]

...出力は次のようになります。

[Object(name=""), Object(name="fake_name")]

式に代入を追加する方法はありますかlambda? 例:

flag = True 
input = [Object(name=""), Object(name="fake_name"), Object(name="")] 
output = filter(
    (lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
    input
)

ベストアンサー1

:=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。これは とは関係なく、Python 2 の一般的な動作です。Python 3 ではの内部で キーワードlambdaを使用してこれを回避できますが、の内部で は使用できません。nonlocaldefnonlocallambda

回避策はあります (下記参照)。ところで...


場合によっては、これを使用して 内のすべての操作を実行できます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オブジェクトがあります。.valuesetattr:

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)

おすすめ記事