1. ホーム
  2. python

[解決済み] Pythonの関数チェイン

2023-01-06 13:59:53

質問

質問 Codewars.com 以下のようなタスクに遭遇しました。

関数を作成する add を作り、連続して呼ばれたときに数字を足し算するようにします。そこで add(1)1 , add(1)(2) を返さなければなりません。 1+2 , ...

私はPythonの基本をよく知っていますが、このように連続して呼び出せる関数、つまり、関数 f(x) として呼び出すことができるような f(x)(y)(z)... . ここまでは、この表記をどう解釈していいのかもわからない。

数学者である私としては f(x)(y) は関数で、すべての x に割り当てる関数です。 g_{x} を返し、その後に g_{x}(y) を返し、同様に f(x)(y)(z) .

この解釈が正しければ、Pythonは私にとって非常に興味深く思える関数を動的に作成することを可能にします。この 1 時間、Web を検索しましたが、正しい方向への手がかりを見つけることができませんでした。しかし、このプログラミングの概念がどのように呼ばれるかを私は知らないので、これはあまり驚くことではないのかもしれません。

この概念をどのように呼び、どこでそれについてもっと読むことができますか?

どのように解決するのですか?

これが 機能 と同じように連鎖しているのか、それとも 呼び出し可能 を連鎖させることができますが、関数 を呼び出すことができるので、害はないと思います。いずれにせよ、私が思いつく方法は2つあります。

サブクラス化 int を定義し __call__ :

最初の方法は、カスタム int サブクラスで __call__ を定義するサブクラスで、更新された値でそれ自身の新しいインスタンスを返します。

class CustomInt(int):
    def __call__(self, v):
        return CustomInt(self + v)

機能 add を返すように定義できるようになりました。 CustomInt インスタンスを返すと定義できるようになり、それ自身の更新された値を返す callable として、連続して呼び出すことができるようになりました。

>>> def add(v):
...    return CustomInt(v)
>>> add(1)
1
>>> add(1)(2)
3
>>> add(1)(2)(3)(44)  # and so on..
50

さらに int のサブクラスとして、返される値には __repr____str__ の動作は int s. しかし、より複雑な操作のためには、他のダンドリを適切に定義する必要があります。 .

コメントで@Caridorcさんが指摘されているように add は単純にこうも書ける。

add = CustomInt 

クラスをリネームして add ではなく CustomInt も同様に動作します。


クロージャを定義し、値を得るために追加の呼び出しを必要とします。

私が思いつく唯一の他の方法は、結果を返すために余分な空の引数の呼び出しを必要とする入れ子関数を含むことです。私は ではなく を使って nonlocal を使わず、Python間で移植できるようにするために関数オブジェクトに属性を付けることを選択します。

def add(v):
    def _inner_adder(val=None):  
        """ 
        if val is None we return _inner_adder.v 
        else we increment and return ourselves
        """
        if val is None:    
            return _inner_adder.v
        _inner_adder.v += val
        return _inner_adder
    _inner_adder.v = v  # save value
    return _inner_adder 

これは継続的に自分自身を返す( _inner_adder ) を返しますが、もし val が指定された場合、それをインクリメントします ( _inner_adder += val )、そうでない場合はそのままの値を返します。先にも述べたように、これには追加の () を呼び出す必要があります。

>>> add(1)(2)()
3
>>> add(1)(2)(3)()  # and so on..
6