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


554

__init____call__メソッドの違いを知りたい。

例えば:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

回答:


755

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

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__

433
そのため、インスタンスを初期化する__init__ためにクラスが呼び出されるときにメソッドが使用され__call__インスタンスが呼び出されるときにメソッドが呼び出されます
pratikm

1
これは正しいようですが、インスタンス変数はインスタンスの存続期間中に変更される可能性があり、場合によっては有益な場合があります。
マーフィー

5
クラスをインスタンス化するときにinitが呼び出されます。myfoo= Foo(1,4,7.8) 呼び出しは、すでにインスタンス化されているクラスを呼び出して何かを行うテンプレートですFoo:\ def __call __(self、zzz)次に、myfoo(12)クラスを呼び出して、そのクラスの機能を実行します。
user1270710

1
注:一般に関数は呼び出し可能であるため、関数は常にメソッド呼び出しをサポートしています。したがって、次のように関数を呼び出すこともできます:myFun .__ call __(arg)
Arindam Roychowdhury

8
の実用的な使い方は__call__何ですか?
mrgloom

262

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

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

In [2]: a = A()
init

In [3]: a()
call

2
__call__インスタンスを関数として使用できるようにするだけでなく、インスタンスが関数として使用されたときに実行される関数本体を定義します。
アーサー、

85

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

クラス(オブジェクト)のインスタンスは、あたかも関数であるかのように扱うことができます。それらを他のメソッド/関数に渡し、それらを呼び出します。これを実現するには、__call__クラス関数を特殊化する必要があります。

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

Pythonでは、__init__()はクラスコンストラクタとして適切に定義されています(__del__()クラスデストラクタも同様です)。したがって、間の正味の違いがある__init__()__call__()第一のクラスのインスタンスを構築し、第二になり、このようなインスタンスの呼び出し可能な関数としては、オブジェクト自体のライフサイクルに影響を与えることなくなり(すなわち、__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

2
概念は理解していますが、内部状態変更するという特別な機能は理解していません。上記のコードでdef __call__単にに置き換えた場合、同じことをdef update行うupdateメソッドをクラスに与えます。以下でとして呼び出された場合、内部状態を変更することもできますs.update(7, 8)。では、__call__syntactixの砂糖はどうでしょうか。
Alex Povel

27

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

技術的に__init____new__、オブジェクトの作成時に一度呼び出されるため、初期化できます。

しかし、オブジェクトを再定義したい場合、たとえば、オブジェクトを使い終わった場合、新しいオブジェクトが必要になる場合など、多くのシナリオがあります。__call__それは新しいであるかのようにあなたが同じオブジェクトを再定義することができます。

これは1つのケースにすぎず、さらに多くのケースが考えられます。


9
この特定のケースでは、新しいインスタンスを作成するだけでよいのではないですか?これは、同じインスタンスを変更して使用するために何らかの方法で効率的ですか?
マーフィー、

19
>>> 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 ... 
>>> 

これは受け入れられる答えだと思います。正確に答えます。
Prasad Raghavendra

18

__init____call__メソッドは何回でもオブジェクトで呼び出せるため、コンストラクタとして扱われます。__init____call__関数はどちらもデフォルトの引数を取ります。


1
__init__はコンストラクタ関数ではありませんが、そう__new__です。__init__直後に呼び出されます__new__
dallonsi

__new__はクラスのインスタンスを作成し、引数としてクラスを受け取ると思います__init__が、インスタンスコンストラクターはそれを受け取る理由selfです。これを確認する簡単な方法はa = Foo(1,2,3)、コンストラクタの引数を受け取る関数を呼び出すこと__init__です。
Coffee_fan

13

フィボナッチシリーズから一定数の用語を印刷したいとします。フィボナッチ数列の最初の2項は1であることを覚えておいてください。例:1、1、2、3、5、8、13 ...

フィボナッチ数を含むリストを1回だけ初期化し、その後更新する必要があります。これで__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__が1回だけ呼び出されたことが確認できる場合は、クラスが最初にインスタンス化されたときに、後でオブジェクトは再初期化せずに呼び出されていました。


7

また__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")

出力

ここに画像の説明を入力してください


4
出力をテキストとしてコピーしていただけませんか?
ソロモンウッコ

このアプローチのポイントは何ですか?別のアプローチと比較できますか?
nealmcb

7

したがって、__init__任意のクラスのインスタンスを作成し、インスタンス変数も初期化するときに呼び出されます。

例:

class User:

    def __init__(self,first_n,last_n,age):
        self.first_n = first_n
        self.last_n = last_n
        self.age = age

user1 = User("Jhone","Wrick","40")

そして__call__、他の関数のようにオブジェクトを呼び出すときに呼び出されます。

例:

class USER:
    def __call__(self,arg):
        "todo here"
         print(f"I am in __call__ with arg : {arg} ")


user1=USER()
user1("One") #calling the object user1 and that's gonna call __call__ dunder functions

1
@Redowan Delowar感謝状
Ayemun Hossain Ashik

4

__init__Pythonクラスの特別なメソッドであり、クラスのコンストラクタメソッドです。これは、クラスのオブジェクトが構築されるたびに呼び出されます。または、新しいオブジェクトを初期化すると言えます。例:

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

我々はA()を使用する場合は、エラーになります TypeError: __init__() missing 1 required positional argument: 'a'、それは1つの引数を必要とするaための__init__

........

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

例:

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__ここには関数がないため、問題なく実行されます。


オブジェクトを初期化されたクラスオブジェクトに渡します。だから呼び出し可能なオブジェクト?
Ciasto piekarz

3

__call__任意の値を返すことができます__init__が、コンストラクターはクラスのインスタンスを暗黙的に返します。他の回答が正しく指摘しているように、初期化されたインスタンスが中間変数に割り当てられている場合に備えて、複数回__init__呼び出すことは可能ですが、1回だけ呼び出され__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'
>>> 

3

短くて甘い答えはすでに上記に提供されています。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は、結果出力に関しては同じように見えます。しかし、scenario1では、別の新しいインスタンスinstance1を再度作成します。scenario2では、作成済みの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;
        }
    }
}

3
Javaとの比較は完全に問題の範囲外です。あなたの例では、それが不十分に選択されたため、何の違いも見られません、数字は同じです。
Aquiles Carattino 2018

2

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")  
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.