在研究Counter
中的python collections
类时,我发现了一些我认为很奇怪的东西:他们没有在self
函数的变量中显式使用__init__
参数。论点。
请参见下面的代码(不带文档字符串直接复制):
class Counter(dict):
def __init__(*args, **kwds):
if not args:
raise TypeError("descriptor '__init__' of 'Counter' object "
"needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 argments, got %d' % len(args))
super(Counter, self).__init__()
self.update(*args, **kwds)
稍后在同一类中,update
和subtract
方法也以相同的方式定义。
在向我提出有关self
在课堂上的工作方式的问题之前,我会指出,我不认为这是重复的问题。我了解self
的工作原理,并且self
不是关键字(只是标准做法)等。我也了解此代码有效(我不怀疑*
的有效性unpack / explode / starred-expressions语法)
我的问题与为什么...
__init__
和其他普通的(非@static
/ @class
方法),我将来应该在什么情况下考虑使用它? self
(例如Counter.__init__(some_counter)
)来调用这些方法?还是其他例子? 我必须认为这与TypeError(“ descriptor ...”)有关。
答案 0 :(得分:18)
此代码旨在使self
仅在位置上。否则,类似
d = {'self': 5}
Counter(**d)
由于__init__
收到两个self
值而失败。
大多数类不需要这种特殊处理,但是Counter
应该像dict
这样处理关键字参数,即使它们是{ {1}}。具有这种处理方式的其他'self'
方法是需要相同的关键字参数行为的方法。
如果您需要在自己的代码中将Counter
作为有效的关键字参数,则应该做类似的事情。
对于self
,在那里可以匹配来自TypeError
的错误消息:
dict.__init__
在实践中最可能实现此目的的方法可能是人们将>>> dict.__init__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__init__' of 'dict' object needs an argument
>>> Counter.__init__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.7/collections/__init__.py", line 560, in __init__
raise TypeError("descriptor '__init__' of 'Counter' object "
TypeError: descriptor '__init__' of 'Counter' object needs an argument
子类化,而忘记将Counter
传递给self
(或使用Counter.__init__
)。