1. ホーム
  2. python

[解決済み] ファンクタを呼び出し可能なクラスとして、またはネストされた関数として作成する [終了] 。

2022-02-17 21:02:44

質問事項

Python 3では、このようにクラスを作成することができます。

class foo:
    def __init__(self, x):
        self.x=x

    def __call__(self, y):
        self.x = self.x + 1
        return (self.x, y)

そして、このような状態でファンクタとして使うことができる。

functor = foo(5)
x = 44354234
print('(1.1) ', functor(7))
print('(1.2) ', functor(8))
print('(1.2) ', functor(9))

実際には、私は関数を返す関数を作りました。しかし、この最初の関数は、実は呼び出し可能なオブジェクトを返すコンストラクタなのです。IMHOでは、開発者がクラスを拡張したり、メソッドを追加したりすることを可能にすることで、これは事態を悪化させる可能性があります。さらに __init__ のコードの方が、なぜか自然に先行しています。 __call__ を実行する必要があるのですが、クラス構成ではそれが明確ではありません。最後に、Python 3 の「方法」は、クラスよりも関数を使うことを提案しています。

このため、私はこのクラスの関数版を作りました。この方が定型的なコードが少なく、より自然に読めると思います。

def bar(x):
    def f(y):
        nonlocal x
        x = x + 1
        return (x,y)
    return f

functor2 = bar(5)
x = 345234234
print('(2.1) ', functor2(7))
print('(2.2) ', functor2(8))
print('(2.3) ', functor2(9))

しかし、それは nonlocal というのは、私が考えていない理由で直感的に理解できないかもしれません。2番目のアプローチは良い習慣ですか、それとも危険な落とし穴があるのでしょうか?Python 3ではどちらを優先すべきでしょうか?特に、私はほとんど経験がないので nonlocal .

解決方法は?

近年のPythonの開発方針は、「他言語のあらゆる機能をPythonに取り込もう」であり、その結果、一つのタスクを様々な方法で達成することができるようになったように見えます。

だから、あることをするのに最適な方法というのはなくて、開発者が何をしたいかによる。ですから Class を使用してステートフルな関数を作成し、それを拡張できるようにすることは、状況によっては必要かもしれません。クロージャを nonlocal の方が一般的であり、直感的でないことはないでしょう。もうひとつの疑問は、この方法をメソッド・デコレータに使う場合、関数ではより少ないコードしか書けず、クラスではより多くの「マジック」を追加しなければならない、ということです。 self .

追伸:Pythonでは、関数に属性を持たせることができるので、同じようにコーディングするもう一つの方法は x の属性として f の代わりにインナー関数 nonlocal しかし、それはあなたが説明したものよりも一般的なアプローチではありません。

def bar(x):
    def f(y):
        f.x=f.x+1
        return (f.x, y)
    f.x=x
    return f

EDIT: return文にインデントを追加しました。