web-dev-qa-db-ja.com

同じインスタンスでクラスを呼び出し可能にする

class Foo(object):
    def tick(self):
        print("something")

class Bar(object):
    def __init__(self):
        self.foo = Foo()

    def tick(self):
        #Here's what I do....
        self.foo.tick()

        #here's what my goal would be
        self.foo()

b = Bar()
b.tick()

それが本質的に私の目標です。集めたものから、ティック関数を__call__に変更することができます。これにより、やりたいことができるようになります。他のいくつかの回答は、これによりオブジェクトの新しいインスタンスが作成されると述べていますが、それはself.fooのメモリを使用することを意味しますか?それとも、新しくインスタンス化されたまったく新しいオブジェクトを作成しますか?またはself.fooのコピーを作成しますか?

また、これには、明らかになる場合と現れない場合がある、いくつかの欠点が思い浮かびます。プログラムの特定の部分について、オブジェクトに__call__があるかどうかを確認して、渡す引数が関数なのか変数なのかを判断しますが、許可したいとは思いません。呼び出されるもの(ただし、その時点ではクラスは技術的には関数になると思います)。関数と呼び出し可能なクラスを区別する方法はありますか?

これを望ましくないものにする他の何かがありますか(そしてそれはPythonicの方法ですか?)?私の次の考えは、接頭辞__が付いた他の変数はクラス外では使用できないということでしたが、ここではそうではないようです。

17
DanielCardin

tick(self)__call__(self)に変更するのが正しい解決策です。

これはメモリ割り当てとは何の関係もありません。 ___call___が意味するのは、構文foo()を(オブジェクトfooに対して)使用するときにPythonが呼び出す関数です。

後の質問については、何かがオブジェクトであるかどうかを確認するには、isinstanceまたはissubclassを使用します(おそらくobjectクラスで)。そして私の心の中では この答え は「何かが関数であるかどうかをどのように判断するのですか?」で受け入れられているものよりも優れています。あなたがおそらく見た質問。

25
Borealid

クラスインスタンスを呼び出し可能にするには、___call___メソッドを実装するだけです。次に、___call___メソッドを呼び出すには、次のようにします。instance(arg1,arg2,...)-つまり、関数を呼び出すのと同じ方法でインスタンスを呼び出します。

必要に応じて、クラスで定義されている他のメソッドで___call___のエイリアスを作成できることに注意してください。

_>>> class Foo(object):
...     def tick(self):
...         print ("something")
...     __call__ = tick
... 
>>> a = Foo()
>>> a()
something
>>> a.tick()
something
_
15
mgilson