我想知道__init__和__call__方法之间的区别。

例如:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

当前回答

我们可以使用调用方法来使用其他类方法作为静态方法。

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__方法可以被对象调用任意次数。__init__和__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

我将尝试用一个例子来解释这一点,假设您想从斐波那契数列中输出固定数量的项。记住斐波那契数列的前两项都是1。例:1,1,2,3,5,8,13 ....

您希望包含斐波那契数的列表只初始化一次,然后更新。现在我们可以使用__call__函数了。阅读@mudit verma的回答。这就像你希望对象作为函数可调用,但不是每次调用时都重新初始化。

Eg:

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__只被调用了一次,那就是类第一次实例化的时候,后来对象被调用而没有重新初始化。

上面已经给出了简短而甜蜜的答案。我想提供一些与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。在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;
        }
    }
}

__init__()可以:

初始化类的实例。 被叫了很多次。 只返回None。

__call__()可以像实例方法一样自由使用。

例如,Person类有__init__()和__call__(),如下所示:

class Person:
    def __init__(self, f_name, l_name):
        self.f_name = f_name
        self.l_name = l_name
        print('"__init__()" is called.')
        
    def __call__(self, arg):
        return arg + self.f_name + " " + self.l_name

现在,我们创建并初始化Person类的实例,如下所示:

    # Here
obj = Person("John", "Smith")

然后调用__init__(),如下所示:

"__init__()" is called.

接下来,我们以如下所示的2种方式调用__call__():

obj = Person("John", "Smith")
print(obj("Hello, ")) # Here
print(obj.__call__("Hello, ")) # Here

然后调用__call__(),如下所示:

"__init__()" is called.
Hello, John Smith # Here
Hello, John Smith # Here

并且,__init__()可以多次调用,如下所示:

obj = Person("John", "Smith")
print(obj.__init__("Tom", "Brown")) # Here
print(obj("Hello, "))
print(obj.__call__("Hello, "))

然后,调用__init__(), Person类的实例被重新初始化,并从__init__()返回None,如下所示:

"__init__()" is called.
"__init__()" is called. # Here
None # Here
Hello, Tom Brown
Hello, Tom Brown

并且,如果__init__()不返回None,我们调用__init__(),如下所示:

class Person:
    def __init__(self, f_name, l_name):
        self.f_name = f_name
        self.l_name = l_name
        print('"__init__()" is called.')
        return "Hello" # Here
        
    # ...

obj = Person("John", "Smith") # Here

出现以下错误:

__init__()应该返回None,而不是'str'

并且,如果Person类中没有定义__call__:

class Person:
    def __init__(self, f_name, l_name):
        self.f_name = f_name
        self.l_name = l_name
        print('"__init__()" is called.')
        
    # def __call__(self, arg):
    #     return arg + self.f_name + " " + self.l_name

然后,我们调用obj("Hello, "),如下所示:

obj = Person("John", "Smith")
obj("Hello, ") # Here

出现以下错误:

'Person'对象不可调用

同样,我们调用obj。__call__("Hello, ")如下所示:

obj = Person("John", "Smith")
obj.__call__("Hello, ") # Here

出现以下错误:

AttributeError: 'Person'对象没有属性'__call__'