web-dev-qa-db-ja.com

__init__と__call__の違いは何ですか?

__init__メソッドと__call__メソッドの違いを知りたいです。

例えば:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20
378
sam

最初のものは新しく作成されたオブジェクトを初期化するために使用され、それを行うために使用される引数を受け取ります。

class Foo:
    def __init__(self, a, b, c):
        # ...

x = Foo(1, 2, 3) # __init__

2番目は関数呼び出し演算子を実装しています。

class Foo:
    def __call__(self, a, b, c):
        # ...

x = Foo()
x(1, 2, 3) # __call__
534
Cat Plus Plus

メタクラスでカスタムの__call__()メソッドを定義すると、常にインスタンス自体を変更するのではなく、クラスのインスタンスを関数として呼び出すことができます。

In [1]: class A:
   ...:     def __init__(self):
   ...:         print "init"
   ...:         
   ...:     def __call__(self):
   ...:         print "call"
   ...:         
   ...:         

In [2]: a = A()
init

In [3]: a()
call
202
avasal

Pythonでは、関数はファーストクラスのオブジェクトです。つまり、関数参照は他の関数やメソッドへの入力で渡し、それらの内部から実行することができます。

クラスのインスタンス(別名オブジェクト)は、あたかもそれらが関数であるかのように扱うことができます。それらを他のメソッド/関数に渡して呼び出します。これを達成するためには、__call__クラス関数は特殊化されなければなりません。

def __call__(self, [args ...])入力として可変数の引数を取ります。 xがクラスXのインスタンスであると仮定すると、x.__call__(1, 2)x(1,2)またはインスタンス自体を関数として呼び出すのと同じです

Pythonでは、__init__()はClass Constructorとして正しく定義されています(__del__()はClass Destructorです)。したがって、__init__()__call__()の間には正味の違いがあります。最初のクラスはClassのインスタンスを構築し、2番目はそのようなインスタンスを呼び出し可能にします。 (つまり__call__は構築/破壊のライフサイクルに影響を与えません)しかし内部状態を変更することができます(下記参照)。

例です。

class Stuff(object):

    def __init__(self, x, y, range):
        super(Stuff, self).__init__()
        self.x = x
        self.y = y
        self.range = range

    def __call__(self, x, y):
        self.x = x
        self.y = y
        print '__call__ with (%d,%d)' % (self.x, self.y)

    def __del__(self):
        del self.x
        del self.y
        del self.range

>>> s = Stuff(1, 2, 3)
>>> s.x
1
>>> s(7, 8)
__call__ with (7,8)
>>> s.x
7
60
Paolo Maresca

__call__はクラスのインスタンスを呼び出し可能にします。なぜ必要なのでしょうか。

技術的には、__init__はobjectが作成されたときに__new__によって一度だけ呼び出されるので、初期化することができます。

しかし、あなたは自分のオブジェクトを再定義したいと思うかもしれない多くのシナリオがあります、あなたがあなたのオブジェクトを使い終えたと言って、そして新しいオブジェクトの必要性を見つけるかもしれません。 __call__を使えば、あたかも新しいオブジェクトと同じオブジェクトを再定義することができます。

これはほんの1つのケースですが、もっとたくさんある可能性があります。

23
Mudit Verma

__init__はコンストラクタとして扱われますが、__call__メソッドはオブジェクトとともに何度でも呼び出すことができます。 __init__関数と__call__関数はどちらもデフォルトの引数を取ります。

14
Vikram
>>> class A:
...     def __init__(self):
...         print "From init ... "
... 
>>> a = A()
From init ... 
>>> a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: A instance has no __call__ method
>>> 
>>> class B:
...     def __init__(self):
...         print "From init ... "
...     def __call__(self):
...         print "From call ... "
... 
>>> b = B()
From init ... 
>>> b()
From call ... 
>>> 
13
Jobin

私は例を使ってこれを説明しようとするでしょう、あなたがフィボナッチ数列から用語の固定数を印刷したいと仮定します。フィボナッチ数列の最初の2用語は1です。例:1、1、2、3、5、8、13 ....

フィボナッチ数を含むリストを一度だけ初期化し、その後更新する必要があります。これで__call__機能を使うことができます。 @mudit vermaの答えを読んでください。オブジェクトを関数として呼び出し可能にしたいが、呼び出すたびに再初期化したくないようなものです。

例えば:

class Recorder:
    def __init__(self):
        self._weights = []
        for i in range(0, 2):
            self._weights.append(1)
        print self._weights[-1]
        print self._weights[-2]
        print "no. above is from __init__"

    def __call__(self, t):
        self._weights = [self._weights[-1], self._weights[-1] + self._weights[-2]]
        print self._weights[-1]
        print "no. above is from __call__"

weight_recorder = Recorder()
for i in range(0, 10):
    weight_recorder(i)

出力は以下のとおりです。

1
1
no. above is from __init__
2
no. above is from __call__
3
no. above is from __call__
5
no. above is from __call__
8
no. above is from __call__
13
no. above is from __call__
21
no. above is from __call__
34
no. above is from __call__
55
no. above is from __call__
89
no. above is from __call__
144
no. above is from __call__

あなたが出力が__init__が一度だけ呼ばれたのを観察するならば、それはクラスが最初にインスタンス化された時です、後でオブジェクトは再初期化なしで呼ばれていました。

8
Ruthvik Vaila

__call__メソッドを使って デコレータを実装することもできます

この例は、 Python 3のパターン、レシピ、熟語 から引用したものです。

class decorator_without_arguments(object):
    def __init__(self, f):
        """
        If there are no decorator arguments, the function
        to be decorated is passed to the constructor.
        """
        print("Inside __init__()")
        self.f = f

    def __call__(self, *args):
        """
        The __call__ method is not called until the
        decorated function is called.
        """
        print("Inside __call__()")
        self.f(*args)
        print("After self.f( * args)")


@decorator_without_arguments
def sayHello(a1, a2, a3, a4):
    print('sayHello arguments:', a1, a2, a3, a4)


print("After decoration")
print("Preparing to call sayHello()")
sayHello("say", "hello", "argument", "list")
print("After first sayHello() call")
sayHello("a", "different", "set of", "arguments")
print("After second sayHello() call")

出力

enter image description here

5
Teoman shipahi

静的メソッドとして他のクラスメソッドを使うためにcallメソッドを使うことができます。

class _Callable:
    def __init__(self, anycallable):
        self.__call__ = anycallable

class Model:

    def get_instance(conn, table_name):

        """ do something"""

    get_instance = _Callable(get_instance)

provs_fac = Model.get_instance(connection, "users")  
2
Abhishek Jain

__call__は任意の値を返すことができますが、__init__はコンストラクタであるため暗黙的にclassのインスタンスを返します。他の答えが正しく指摘しているように、__init__は一度だけ呼び出されますが、初期化されたインスタンスが中間変数に割り当てられている場合は__call__を複数回呼び出すことが可能です。

>>> class Test:
...     def __init__(self):
...         return 'Hello'
... 
>>> Test()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: __init__() should return None, not 'str'
>>> class Test2:
...     def __call__(self):
...         return 'Hello'
... 
>>> Test2()()
'Hello'
>>> 
>>> Test2()()
'Hello'
>>> 
2
Dmitriy Sintsov

短くて甘い答えはすでに上で提供されています。私はJavaと比べて実用的な実装をいくつか提供したいと思います。

 class test(object):
        def __init__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c
        def __call__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c


    instance1 = test(1, 2, 3)
    print(instance1.a) #prints 1

    #scenario 1
    #creating new instance instance1
    #instance1 = test(13, 3, 4)
    #print(instance1.a) #prints 13


    #scenario 2
    #modifying the already created instance **instance1**
    instance1(13,3,4)
    print(instance1.a)#prints 13

:シナリオ1とシナリオ2は結果出力の点で同じようです。しかしシナリオ1では、もう一度別の新しいインスタンスinstance1を作成します。シナリオ2では、作成済みのinstance1を単純に変更します。 __call__はシステムが新しいインスタンスを作成する必要がないのでここでは有益です。

Javaと同等

public class Test {

    public static void main(String[] args) {
        Test.TestInnerClass testInnerClass = new Test(). new TestInnerClass(1, 2, 3);
        System.out.println(testInnerClass.a);

        //creating new instance **testInnerClass**
        testInnerClass = new Test().new TestInnerClass(13, 3, 4);
        System.out.println(testInnerClass.a);

        //modifying already created instance **testInnerClass**
        testInnerClass.a = 5;
        testInnerClass.b = 14;
        testInnerClass.c = 23;

        //in python, above three lines is done by testInnerClass(5, 14, 23). For this, we must define __call__ method

    }

    class TestInnerClass /* non-static inner class */{

        private int a, b,c;

        TestInnerClass(int a, int b, int c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }
}
2
Uddhav Gautam

__init__はPythonのクラスでは特別なメソッドです、それはクラスのコンストラクタメソッドです。それはクラスのオブジェクトが構築されるときはいつでも呼ばれるか、それが新しいオブジェクトを初期化すると言うことができます。例:

    In [4]: class A:
   ...:     def __init__(self, a):
   ...:         print(a)
   ...:
   ...: a = A(10) # An argument is necessary
10

A()を使用すると、__init__のために1つの引数aが必要なので、エラーTypeError: __init__() missing 1 required positional argument: 'a'が発生します。

........

__call__をClassに実装すると、Classインスタンスを関数呼び出しとして呼び出すことができます。

例:

In [6]: class B:
   ...:     def __call__(self,b):
   ...:         print(b)
   ...:
   ...: b = B() # Note we didn't pass any arguments here
   ...: b(20)   # Argument passed when the object is called
   ...:
20

ここでB()を使用した場合、ここでは__init__関数がないため、問題なく動作します。

1
bhatnaushad