development

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

big-blog 2020. 2. 18. 22:49
반응형

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


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

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

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

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

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__()메타 클래스에서 커스텀 메소드를 정의 하면 클래스 자체가 항상 수정되는 것이 아니라 클래스의 인스턴스를 함수로 호출 할 수 있습니다.

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

In [2]: a = A()
init

In [3]: a()
call

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

클래스 인스턴스 (일명 개체)는 마치 함수 인 것처럼 취급 할 수 있습니다. 다른 메서드 / 함수로 전달하고 호출합니다. 이를 위해서는 __call__클래스 기능이 특화되어야합니다.

def __call__(self, [args ...])가변 개수의 인수를 입력으로 사용합니다. 가정 x클래스의 인스턴스 인 X, x.__call__(1, 2)호출과 유사 x(1,2)또는 함수 자체를 인스턴스 .

파이썬에서는 __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

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

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

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

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


__init____call__메소드를 객체로 여러 번 호출 할 수있는 생성자로 취급됩니다 . __init____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 ... 
>>> 

피보나치 시리즈에서 고정 된 수의 용어를 인쇄하려고한다고 가정 해 보겠습니다. 피보나치 시리즈의 처음 두 항은 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__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 메소드를 사용하여 다른 클래스 메소드를 정적 메소드로 사용할 수 있습니다 .

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")  

__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;
        }
    }
}

참고 URL : https://stackoverflow.com/questions/9663562/what-is-the-difference-between-init-and-call



도와주세요.
반응형