__init__ 还是 __call__?

12

我应该何时使用 __init__ 方法和 __call__ 方法?

我不确定应该使用哪个方法。

目前我两种方法都可以使用,但我不知道哪个更为合适。


2
你想要做什么? - arshajii
你可以同时使用它们,并且实现它们。如果你不告诉我们你想做什么,我们怎么能帮助你呢?你觉得文档有些难以理解吗?是哪个部分让你感到困惑? - David Heffernan
2
相关:https://dev59.com/Ymkw5IYBdhLWcg3wwdUS - Ashwini Chaudhary
可能是Python中__init__和__call__的区别是什么?的重复问题。 - wombatonfire
4个回答

21

这两者完全不同。

__init__()是构造函数,在对象的新实例上运行。

__call__()在您尝试调用对象的实例,就像它是一个函数一样时运行。

例如:假设我们有一个名为Test的类:

a = Test() #This will call Test.__init__() (among other things)
a() #This will call Test.__call__()

1
除非它们被制作成相同的东西,否则我会构建可调用迭代器的惰性字符串分词器类。为了保持实现DRY并为用户提供等效的API,__call __()返回self,而__init __()使用相同的参数调用__call __()。 想象一下tokens = list(Tokenizer(doc, ngrams=2))tokenizer = Tokenizer(); tokens = list(tokenizer(doc, ngrams=2))list(tokenizer.tokenize(doc, ngrams=2))是相同的。无论用户喜欢如何使用它,它都可以“正常工作”。 - hobs
@hobs,很好的例子!为什么不把它作为答案呢? - wombatonfire
关于@hobs的建议,值得注意的是这是一个相当罕见的用例。一般来说,我想不出有多少情况需要那种行为 - 一个单一一致的使用方式通常比有很多方式更好,因为它使代码更易于阅读。 - Gareth Latty
@GarethLatty 很好的观点。不太符合Python风格。只有在你有非常好的理由时才建议这样做。我只是为了模仿NLTK包而这样做的。长期存在的包,尤其是具有大量API更新的包,往往有很多方法可以完成相同的事情,特别是对于像Tokenizer这样需要作为配置对象传递、在管道中作为函数调用、以配置形式进行pickle/depickle、作为参数传递给期望可调用对象的东西等可调用类。 - hobs

9

一个快速测试可以展示它们之间的差异。

class Foo(object):
    def __init__(self):
        print "init"
    def __call__(self):
        print "call"

f = Foo()  # prints "init"
f()        # prints "call"

这些绝对不能互换使用


7

大多数情况下,您希望使用__init__。这是用于初始化类的新实例的方法,您通过调用类来创建该实例。 __call__是为了使您的实例可被调用。虽然偶尔会用到,但并不常见,但这可能是有用的。以下示例应该说明:

>>> class C(object):
...   def __init__(self):
...     print 'init'
...   def __call__(self):
...     print 'call'
... 
>>> c = C()
init
>>> c()
call
>>> 

2
一个简单的代码片段将更好地阐述这一点。
>>> class Math:
...     def __init__(self):
...             self.x,self.y=20,30
...     def __call__(self):
...             return self.x+self.y
... 
>>> m=Math()
>>> m()
50

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接