__init__와 __call__의 차이점은 무엇입니까?


554

__init____call__방법 의 차이점을 알고 싶습니다 .

예를 들면 다음과 같습니다.

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

답변:


754

첫 번째는 새로 작성된 객체를 초기화하는 데 사용되며이를 수행하는 데 사용되는 인수를 수신합니다.

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__

433
그래서, __init__때 방법을 사용하는 클래스 인스턴스를 초기화라고는 동안 __call__때 메소드가 호출 인스턴스 라고합니다
pratikm

1
맞습니다. 인스턴스 변수는 인스턴스 수명 동안 수정 될 수 있으며 경우에 따라 도움이 될 수 있습니다.
Murphy

5
클래스를 인스턴스화 할 때 init 가 호출됩니다 : myfoo = Foo (1,4,7.8) call 은 이미 인스턴스화 된 클래스를 호출하여 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__인스턴스를 함수로 사용할 수있을뿐만 아니라 인스턴스가 함수로 사용될 때 실행되는 함수 본문을 정의합니다.
Arthur

85

파이썬에서 함수는 일류 객체입니다. 즉, 함수 참조는 다른 함수 및 / 또는 메소드에 입력으로 전달되어 그 안에서 실행될 수 있습니다.

클래스 인스턴스 (일명 개체)는 마치 함수 인 것처럼 취급 할 수 있습니다. 다른 메서드 / 함수로 전달하고 호출합니다. 이를 위해서는 __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

2
개념을 이해하지만 내부 상태수정 하는 특별한 기능은 아닙니다 . 위의 코드에서 def __call__간단히로 대체 하면 def update클래스 update에 동일한 작업을 수행 하는 메서드를 제공합니다 . 아래와 같이 호출되면 내부 상태를 수정할 수도 있습니다 s.update(7, 8). 그럼 __call__그냥 syntactix 설탕입니까?
Alex Povel

27

__call__클래스의 인스턴스를 호출 가능하게 만듭니다. 왜 필요할까요?

기술적 __init__으로 __new__객체가 생성 될 때 한 번 호출 되므로 초기화 할 수 있습니다.

그러나 객체를 재정의하고, 객체를 다 사용했다고 말하고, 새로운 객체가 필요할 수있는 시나리오가 많이 있습니다. 로 __call__가 새 것처럼 당신이 동일한 개체를 다시 정의 할 수 있습니다.

이것은 하나의 경우에 불과하며 더 많은 것이있을 수 있습니다.


9
이 특정한 경우에 우리는 단지 새로운 인스턴스를 생성하지 않아야 하는가? 동일한 인스턴스를 수정하고 사용하는 데 어떤면에서 효율적입니까?
Murphy

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

피보나치 시리즈에서 고정 된 수의 용어를 인쇄하려고한다고 가정 해 보겠습니다. 피보나치 시리즈의 처음 두 항은 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__클래스가 처음으로 인스턴스화되었을 때 한 번만 출력 이 호출 된 것을 관찰하면 나중에 다시 초기화하지 않고 오브젝트가 호출되었습니다.


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
출력물을 텍스트로 복사 할 수 있습니까?
솔로몬 Ucko

이 접근법의 요점은 무엇입니까? 다른 접근 방식과 대조 할 수 있습니까?
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 감사 broh
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'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__여기 에 함수 가 없으므로 제대로 실행 됩니다.


초기화 된 클래스 객체에 객체 전달 그래서 호출 가능한 객체?
Ciasto piekarz 19

3

__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'
>>> 

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을 만듭니다 . 시나리오 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;
        }
    }
}

3
Java와 비교하는 것은 완전히 문제의 범위를 벗어납니다. 귀하의 예에서, 잘못 선택되었으므로 차이가 표시되지 않으며 숫자는 동일합니다.
Aquiles Carattino

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.