__init__和__call__有什么区别?


553

我想知道其中的差别之间__init____call__方法。

例如:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

Answers:


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__

432
因此,__init__当使用方法调用初始化实例,而__call__当调用该方法的实例被称为
pratikm

1
这似乎是正确的,显然实例变量可以在实例生命周期内进行修改,这在某些情况下可能是有益的。
墨菲

5
实例化类时会调用init:myfoo = Foo(1,4,7.8) 调用是一个模板,用于调用已实例化的类来做某事,比如说类Foo:\ def __call __(self,zzz)然后,myfoo(12)调用该类以执行该类的工作。
user1270710

1
请注意:由于函数通常是可调用的,因此它们始终支持方法call。因此,您也可以这样调用函数: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是Class的实例Xx.__call__(1, 2)类似于调用实例x(1,2)将实例本身作为函数

在Python中,__init__()正确定义为Class Constructor(以及__del__()Class Destructor)。因此,__init__()和之间有一个净的区别__call__():第一个建立一个Class的实例,第二个使该实例作为一个函数可调用而不会影响对象本身的生命周期(即__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__合成糖吗?
Alex Povel

27

__call__使类的实例可调用。为什么会要求它?

从技术上讲__init____new__创建对象时会调用一次,以便可以对其进行初始化。

但是在许多情况下,您可能想重新定义对象,例如您已经完成了对象的工作,并可能需要一个新的对象。使用,__call__您可以像重新定义一样重新定义相同的对象。

这只是一种情况,可能还有更多。


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__将被视为构造函数,其中as __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 ...

您希望包含斐波那契数字的列表仅被初始化一次,然后更新。现在我们可以使用该__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 Patterns,Recipes和Idioms

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'a由于,它将需要1个参数__init__

........

__call__ 在Class中实现时,可帮助我们将Class实例作为函数调用来调用。

例:

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__函数。


将对象传递给初始化的类对象。那么可调用对象呢?
贾斯托·皮耶卡兹

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在结果输出方面似乎相同。但是在方案1中,我们再次创建另一个新实例instance1。在方案2中,我们只需修改已创建的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

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")  
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.