__init__ 和 __call__ 有什么区别?[重复]

2025-02-28 08:22:00
admin
原创
72
摘要:问题描述:__init__我想知道和__call__方法 之间的区别。例如:class test: def __init__(self): self.a = 10 def __call__(self): b = 20 解决方案 1:第一个用于初始化新创建的对象,并接收用于执行此操...

问题描述:

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

例如:

class test:

  def __init__(self):
    self.a = 10

  def __call__(self): 
    b = 20

解决方案 1:

第一个用于初始化新创建的对象,并接收用于执行此操作的参数:

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__

解决方案 2:

定义自定义__call__()方法允许将类的实例作为函数调用,而不是总是修改实例本身。

In [1]: class A:
   ...:     def __init__(self):
   ...:         print "init"
   ...:         
   ...:     def __call__(self):
   ...:         print "call"
   ...:         
   ...:         

In [2]: a = A()
init

In [3]: a()
call

解决方案 3:

在 Python 中,函数是第一类对象,这意味着:函数引用可以作为输入传递给其他函数和/或方法,并从它们内部执行。

类的实例(又称对象)可以被视为函数:将它们传递给其他方法/函数并调用它们。为了实现这一点,__call__类函数必须是专门的。

def __call__(self, [args ...])
它以可变数量的参数作为输入。假设x是类的一个实例Xx.__call__(1, 2)类似于调用x(1,2)将实例本身作为函数

在 Python 中,__init__()被正确定义为类构造函数(以及是类析构函数)。因此,和__del__()之间存在一个净​​区别:前者构建类的实例,后者使此类实例可像函数一样调用,而不会影响对象本身的生命周期(即不影响构造/析构生命周期),但它可以修改其内部状态(如下所示)。__init__()`__call__()`__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

解决方案 4:

>>> 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 ... 
>>> 

解决方案 5:

__call__使类的实例可调用。为什么需要它?

从技术上讲,在创建对象时__init__会调用一次__new__,以便可以初始化它。

但在许多情况下,您可能想要重新定义对象,比如说您已经完成了对象使用,可能需要一个新对象。__call__您可以重新定义同一个对象,就像它是新对象一样。

这只是一个案例,可能还有很多案例。

解决方案 6:

__init__将被视为构造函数,而__call__方法可以使用对象调用任意次。__init____call__函数都采用默认参数。

解决方案 7:

我将尝试使用一个例子来解释这一点,假设您想要打印斐波那契数列的固定项数。请记住,斐波那契数列的前 2 项是 1。例如:1、1、2、3、5、8、13....

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

例如:

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__仅被调用一次,那就是第一次实例化类时,稍后该对象就会被调用而无需重新初始化。

解决方案 8:

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

解决方案 9:

因此,__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

解决方案 10:

您还可以使用__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")

输出

在此处输入图片描述

解决方案 11:

案例 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)

跑步:

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)

跑步:

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

结果:

- init 1 2 3
- call 7 8 9

解决方案 12:

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

接下来我们__call__()通过如下2种方式调用:

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被重新初始化并None返回,__init__()如下所示:

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

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

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

解决方案 13:

上面已经提供了简短而贴心的答案。我想提供一些与 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。在场景 2 中,我们只需修改已创建的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;
        }
    }
}

解决方案 14:

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

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

如果我们使用 A(),它将会给出错误
,因为TypeError: __init__() missing 1 required positional argument: 'a'它需要 1 个参数。a`__init__`

........

__call__当在类中实现时帮助我们以函数调用的形式调用类实例。

例子:

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__函数。

解决方案 15:

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

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

解决方案 16:

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

实例化类并立即调用

在许多情况下,例如当需要发出 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")

解决方案 17:

call方法用于使对象像函数一样运行。

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

<*There is no __call__ method so it doesn't act like function and throws error.*>

>>> 
>>> class B:
...     def __init__(self):
...         print "From init ... "
...     def __call__(self):
...         print "From call it is a function ... "
... 
>>> b = B()
From init ... 
>>> b()
From call it is a function... 
>>> 

<* __call__ method made object "b" to act like function *>

我们还可以将其传递给类变量。

class B:
    a = A()
    def __init__(self):
       print "From init ... "
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2941  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1803  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色。然而,在实际运行中,资源冲突是经常会遇到的难题。资源冲突可能导致项目进度延迟、成本增加以及产品质量下降等一系列问题,严重影响企业的效益与竞争力。因此,如何有效应对PLM系统中的资源冲突,成为众多企业关注的焦点。接下来,我们将详细探讨5...
plm项目管理系统   31  
  敏捷项目管理与产品生命周期管理(PLM)的融合,正成为企业在复杂多变的市场环境中提升研发效率、增强竞争力的关键举措。随着技术的飞速发展和市场需求的快速更迭,传统的研发流程面临着诸多挑战,而将敏捷项目管理理念融入PLM,有望在2025年实现研发流程的深度优化,为企业创造更大的价值。理解敏捷项目管理与PLM的核心概念敏捷项...
plm项目   31  
  模块化设计在现代产品开发中扮演着至关重要的角色,它能够提升产品开发效率、降低成本、增强产品的可维护性与可扩展性。而产品生命周期管理(PLM)系统作为整合产品全生命周期信息的关键平台,对模块化设计有着强大的支持能力。随着技术的不断发展,到 2025 年,PLM 系统在支持模块化设计方面将有一系列令人瞩目的技术实践。数字化...
plm软件   28  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用