回答:
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__
__call__
何ですか?
__call__()
メタクラスでカスタムメソッドを定義すると、クラスのインスタンスを関数として呼び出すことができ、必ずしもインスタンス自体を変更することはできません。
In [1]: class A:
...: def __init__(self):
...: print "init"
...:
...: def __call__(self):
...: print "call"
...:
...:
In [2]: a = A()
init
In [3]: a()
call
__call__
インスタンスを関数として使用できるようにするだけでなく、インスタンスが関数として使用されたときに実行される関数本体を定義します。
Pythonでは、関数はファーストクラスのオブジェクトです。つまり、関数参照を入力で他の関数やメソッドに渡し、それらの内部から実行できます。
クラス(オブジェクト)のインスタンスは、あたかも関数であるかのように扱うことができます。それらを他のメソッド/関数に渡し、それらを呼び出します。これを実現するには、__call__
クラス関数を特殊化する必要があります。
def __call__(self, [args ...])
入力として可変数の引数を取ります。仮定するとx
、クラスのインスタンスであるX
、x.__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
def __call__
単にに置き換えた場合、同じことをdef update
行うupdate
メソッドをクラスに与えます。以下でとして呼び出された場合、内部状態を変更することもできますs.update(7, 8)
。では、__call__
syntactixの砂糖はどうでしょうか。
__call__
クラスのインスタンスを呼び出し可能にします。なぜそれが必要なのでしょうか?
技術的に__init__
は__new__
、オブジェクトの作成時に一度呼び出されるため、初期化できます。
しかし、オブジェクトを再定義したい場合、たとえば、オブジェクトを使い終わった場合、新しいオブジェクトが必要になる場合など、多くのシナリオがあります。__call__
それは新しいであるかのようにあなたが同じオブジェクトを再定義することができます。
これは1つのケースにすぎず、さらに多くのケースが考えられます。
>>> 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 ...
>>>
__init__
__call__
メソッドは何回でもオブジェクトで呼び出せるため、コンストラクタとして扱われます。__init__
と__call__
関数はどちらもデフォルトの引数を取ります。
__init__
はコンストラクタ関数ではありませんが、そう__new__
です。__init__
直後に呼び出されます__new__
__new__
はクラスのインスタンスを作成し、引数としてクラスを受け取ると思います__init__
が、インスタンスコンストラクターはそれを受け取る理由self
です。これを確認する簡単な方法はa = Foo(1,2,3)
、コンストラクタの引数を受け取る関数を呼び出すこと__init__
です。
フィボナッチシリーズから一定数の用語を印刷したいとします。フィボナッチ数列の最初の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回だけ呼び出されたことが確認できる場合は、クラスが最初にインスタンス化されたときに、後でオブジェクトは再初期化せずに呼び出されていました。
また__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")
出力:
したがって、__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
__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__
ここには関数がないため、問題なく実行されます。
__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'
>>>
短くて甘い答えはすでに上記に提供されています。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;
}
}
}
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")
__init__
ためにクラスが呼び出されるときにメソッドが使用され__call__
、インスタンスが呼び出されるときにメソッドが呼び出されます