To understand *args and **kwargs I made some searchs about, when I fell on this question *args and **kwargs?
The answer below the chosen answer caught my attention,
Your Foo.__init__()
does not support arbitrary keyword arguments. You can add **kw
to it's signature to make it accept them:
class Foo(object):
def __init__(self, value1, value2, **kw):
print 'I think something is being called here'
print value1, value2, kw
Keyword parameters are matched only with arguments with exact matching keyword names; your Foo
method would need to have Python
and stack
keyword parameters. If no matching keyword parameter are found but a **kw
parameter is, they are collected in that parameter instead.
If your subclass knows that the parent class only has positional arguments, you can always pass in positionals:
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print args, kwargs
while len(args) < 2:
args += kwargs.popitem()
super(MyFoo, self).__init__(*args[:2])
where you now must pass in two or more arguments to MyFoo
for the call to work.
In essence, super().methodname
returns a reference to the bound method; from there on out it is a normal method, so you need to pass in arguments that any method can accept. If your method doesn't accept keyword arguments, you get an exception.
I think it is worth adding that this can be used to simplify the __init__ signatures in the child classes. The positional arguments are pealed off from left to right so if you add them to the front and pass the rest to args and kwargs you can avoid mistakes from forgetting to add them explicitly to each of the children. There is some discussion about if that is an acceptable exception "explicit is better than implicit" here. For long lists of args in deep hierarchy this may be clearer and easier to maintain.
To modify this example, I add not_for_Foo to the front of MyFoo and pass the rest through super.
class Foo(object):
def __init__(self, a_value1, a_value2, a_stack=None, *args, **kwargs):
"""do something with the values"""
super(Foo, self).__init__(*args, **kwargs) # to objects constructor fwiw, but object.__init__() takes no args
self.value1 = a_value1
self.value2 = a_value2
self.stack = a_stack
return
def __str__(self):
return ', '.join(['%s: %s' % (k, v) for k, v in self.__dict__.items()])
class MyFoo(Foo):
def __init__(self, not_for_Foo, *args, **kwargs):
# do something else, don't care about the args
super(MyFoo, self).__init__(*args, **kwargs)
self.not_for_Foo = not_for_Foo # peals off
self.myvalue1 = 'my_' + self.value1 # already set by super
if __name__ == '__main__':
print 'Foo with args'
foo = Foo('Python', 2.7, 'my stack')
print foo
print '\nMyFoo with kwargs'
myfoo = MyFoo('my not for foo', value2=2.7, value1='Python', stack='my other stack')
print myfoo
$ python argsNkwargs.py
Foo with args
value2: 2.7, value1: Python, stack: my stack
MyFoo with kwargs
myvalue1: my_Python, not_for_Foo: my not for foo, value2: 2.7, value1:
Python, stack: my other stack
-lrm
When you do this:
super(MyFoo, self).__init__(*args, **kwargs)
It is the same as if you did this, base on how your code is working:
super(MyFoo, self).__init__("python", 2.7, stack="overflow")
However, the __init__
function of Foo
(from which MyFoo
inherits) doesn't support a keyword argument named "stack".
The reason is all the arguments are already unpacked into kwargs and it is a dict now. and you are trying to pass it to a normal variables.
def bun(args,kwargs):
print 'i am here'
print kwargs
def fun(*args,**kwargs):
print kwargs
bun(*args,**kwargs)
fun(hill=3,bi=9) # will fail.
def bun(*args,**kwargs):
print 'i am here'
print kwargs
def fun(*args,**kwargs):
print kwargs
bun(*args,**kwargs) # will work.
fun(hill=3,bi=9)
Try making the modification at
class Foo(object):
def __init__(self, *value1, **value2):
# do something with the values
print 'I think something is being called here'
print value1, value2
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print args, kwargs
super(MyFoo, self).__init__(*args, **kwargs)
foo = MyFoo('Python', 2.7, stack='overflow'
should work..!