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

例如:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

当前回答

你也可以使用__call__方法来实现装饰器。

这个例子来自Python 3模式,食谱和习语

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")

输出:

其他回答

在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

__init__是Python类中的一个特殊方法,它是类的构造函数方法。每当构造类的对象时调用它,或者我们可以说它初始化了一个新对象。 例子:

    In [4]: class A:
   ...:     def __init__(self, a):
   ...:         print(a)
   ...:
   ...: a = A(10) # An argument is necessary
10

如果我们使用A(),它会给出一个错误 TypeError: __init__()缺少一个必需的位置参数:'a',因为它需要一个参数a,因为__init__。

……

当在Class中实现__call__时,可以帮助我们将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__函数。

我将尝试用一个例子来解释这一点,假设您想从斐波那契数列中输出固定数量的项。记住斐波那契数列的前两项都是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__只被调用了一次,那就是类第一次实例化的时候,后来对象被调用而没有重新初始化。

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

__init__将被视为构造函数,其中__call__方法可以被对象调用任意次数。__init__和__call__函数都接受默认参数。