我想知道__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
当前回答
__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'
>>>
其他回答
第一个用于初始化新创建的对象,并接收用于初始化的参数:
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__允许返回任意值,而__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'
>>>
>>> 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 ...
>>>
我想提供一些捷径和语法糖,以及一些可以使用的技术,但我在当前的答案中没有看到它们。
实例化类并立即调用它
在很多情况下,例如当需要做一个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")