답변:
첫 번째는 새로 작성된 객체를 초기화하는 데 사용되며이를 수행하는 데 사용되는 인수를 수신합니다.
class Foo:
def __init__(self, a, b, c):
# ...
x = Foo(1, 2, 3) # __init__
두 번째는 함수 호출 연산자를 구현합니다.
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__
인스턴스를 함수로 사용할 수있을뿐만 아니라 인스턴스가 함수로 사용될 때 실행되는 함수 본문을 정의합니다.
파이썬에서 함수는 일류 객체입니다. 즉, 함수 참조는 다른 함수 및 / 또는 메소드에 입력으로 전달되어 그 안에서 실행될 수 있습니다.
클래스 인스턴스 (일명 개체)는 마치 함수 인 것처럼 취급 할 수 있습니다. 다른 메서드 / 함수로 전달하고 호출합니다. 이를 위해서는 __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__
가 새 것처럼 당신이 동일한 개체를 다시 정의 할 수 있습니다.
이것은 하나의 경우에 불과하며 더 많은 것이있을 수 있습니다.
>>> 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__
.
피보나치 시리즈에서 고정 된 수의 용어를 인쇄하려고한다고 가정 해 보겠습니다. 피보나치 시리즈의 처음 두 항은 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__
클래스가 처음으로 인스턴스화되었을 때 한 번만 출력 이 호출 된 것을 관찰하면 나중에 다시 초기화하지 않고 오브젝트가 호출되었습니다.
데코레이터__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'
로 a
인해 1 개의 인수가 필요하므로 오류가 발생
합니다 __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__
한 번만 호출되지만 __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을 만듭니다 . 시나리오 2에서는 이미 작성된 instance1 만 수정 합니다 . __call__
시스템이 새 인스턴스를 만들 필요가 없으므로 여기에서 유리합니다.
자바와 동일
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;
}
}
}
__init__
때 방법을 사용하는 클래스 인스턴스를 초기화라고는 동안__call__
때 메소드가 호출 인스턴스 라고합니다