我想知道__init__和__call__方法之间的区别。
例如:
class test:
def __init__(self):
self.a = 10
def __call__(self):
b = 20
我想知道__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__使类的实例可调用。 为什么需要它?
从技术上讲,__init__在对象创建时由__new__调用一次,以便可以初始化它。
但是在许多情况下,您可能想要重新定义对象,例如您已经完成了对象,并且可能发现需要一个新对象。使用__call__,你可以重新定义相同的对象,就像它是新的一样。
这只是一个案例,可能还有更多。
案例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
上面已经给出了简短而甜蜜的答案。我想提供一些与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;
}
}
}
我想提供一些捷径和语法糖,以及一些可以使用的技术,但我在当前的答案中没有看到它们。
实例化类并立即调用它
在很多情况下,例如当需要做一个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")
在Python中,函数是一级对象,这意味着:函数引用可以在输入中传递给其他函数和/或方法,并在它们内部执行。
类的实例(又名对象),可以像函数一样对待:将它们传递给其他方法/函数并调用它们。为了实现这一点,__call__类函数必须特殊化。
Def __call__(self, [args…]) 它接受可变数量的参数作为输入。假设x是类x的实例,x.__call__(1,2)类似于将x(1,2)或实例本身作为函数调用。
在Python中,__init__()被正确地定义为类构造函数(以及__del__()是类析构函数)。因此,在__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