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

例如:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

当前回答

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

其他回答

上面已经给出了简短而甜蜜的答案。我想提供一些与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__将被视为构造函数,其中__call__方法可以被对象调用任意次数。__init__和__call__函数都接受默认参数。

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

我想提供一些捷径和语法糖,以及一些可以使用的技术,但我在当前的答案中没有看到它们。

实例化类并立即调用它

在很多情况下,例如当需要做一个APi请求时,逻辑被封装在一个类中,我们真正需要的只是把数据给那个类,并立即作为一个单独的实体运行它,实例化类可能不需要。这就是

instance = MyClass() # instanciation
instance() # run the instance.__call__()
# now instance is not needed 

相反,我们可以这样做。

class HTTPApi:

    def __init__(self, val1, val2):
        self.val1 = val1
        self.val2 = val2

    def __call__(self, *args, **kwargs):
        return self.run(args, kwargs)

    def run(self, *args, **kwargs):
        print("hello", self.val1, self.val2, args, kwargs)
        
if __name__ == '__main__':
    # Create a class, and call it
    (HTTPApi("Value1", "Value2"))("world", 12, 213, 324, k1="one", k2="two")


给调用另一个现有的方法

我们也可以向__call__声明一个方法,而不需要创建一个实际的__call__方法。

class MyClass:

    def __init__(self, val1, val2):
        self.val1 = val1
        self.val2 = val2

    def run(self, *args, **kwargs):
        print("hello", self.val1, self.val2, args, kwargs)

    __call__ = run

if __name__ == '__main__':
    (MyClass("Value1", "Value"))("world", 12, 213, 324, k1="one", k2="two")

这允许声明另一个全局函数而不是一个方法,无论出于什么原因(可能有一些原因,例如你不能修改该方法,但你需要由类调用它)。

def run(self, *args, **kwargs):
    print("hello",self.val1, self.val2,  args, kwargs)

class MyClass:

    def __init__(self, val1, val2):
        self.val1 = val1
        self.val2 = val2

    __call__ = run

if __name__ == '__main__':
    (MyClass("Value1", "Value2"))("world", 12, 213, 324, k1="one", k2="two")

案例1:

class Example:
    def __init__(self, a, b, c):
        self.a=a
        self.b=b
        self.c=c
        print("init", self.a, self.b, self.c)

Run:

Example(1,2,3)(7,8,9)

结果:

- init 1 2 3
- TypeError: 'Example' object is not callable

案例2:

class Example:
    def __init__(self, a, b, c):
        self.a=a
        self.b=b
        self.c=c
        print("init", self.a, self.b, self.c)
    def __call__(self, x, y, z):
        self.x=x
        self.y=y
        self.z=z
        print("call", self.x, self.y, self.z)

Run:

Example(1,2,3)(7,8,9)

结果:

- init 1 2 3
- call 7 8 9