Reputation: 10252
Here is my code snappt:
class C(dict):
def __init__(*args, **kwds):
print 'args = {}'.format(args)
print 'kwds = {}'.format(kwds)
if not args:
raise TypeError("descriptor '__init__' of 'Counter' object needs an argument")
self = args[0]
args = args[1:]
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
super(C, self).__init__()
if __name__ == '__main__':
c = C()
When i run this code, i am confused with the output:
C:\Users\elqstux\Desktop>python wy.py
args = ({},)
kwds = {}
For c = C()
, i think the code will raise a Error, because args
will be ()
in this case, but from the output, args
is ({},)
, what't the reason?
self, args = args[0], args[1:] # allow the "self" keyword be passed
Upvotes: 4
Views: 114
Reputation: 155438
*args
is ({},)
because you didn't declare an explicit self
parameter. So when __init__
is called, the self
parameter ends up becoming the first element in args
. Since you inherit from dict
, you get dict
's repr
, which is {}
.
This trick is used intentionally in Python's dict
subclasses nowadays, because otherwise code that initialized the dict
subclass with mydict(self=123)
would break the initializer. The fix is to do:
def __init__(*args, **kwargs):
self, *args = args
# On Python 2 without unpacking generalizations you'd use the more repetitive:
# self, args = args[0], args[1:]
which forces self
to be accepted purely as a positional argument (which is passed implicitly by the instance construction machinery). For an example of real world usage, see the implementation of collections.Counter
.
Upvotes: 6
Reputation: 24052
Your class __init__
function is being called with a single argument, the implicit self
argument (i.e., the new class instance that's being created). Normally this would print as a class instance. But because the class subclasses dict
, it prints as a dict
, initially with no elements.
Upvotes: 1
Reputation: 229391
I was intrigued by your output! The reason is clear enough: you ommitted self
from the __init__
function definition. Running the example with a regular class will make it clear what happened:
>>> class C():
... def __init__(*args, **kwargs):
... print args, kwargs
...
>>> C()
(<__main__.C instance at 0x103152368>,) {}
<__main__.C instance at 0x103152368>
Of course, self
got stuck into args
as the single element of the args
tuple. self
is just like any other argument, after all.
What made it more puzzling in your case is that since you subclassed dict
, the repr()
of your class at that point was {}
, i.e. the repr()
of an empty dict. Hence the ({},)
.
Upvotes: 3