Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't pass *args and **kwargs in __init__ of a child class

Tags:

python

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, which is this:

class Foo(object):
    def __init__(self, value1, value2):
    # do something with the values
        print value1, value2

class MyFoo(Foo):
    def __init__(self, *args, **kwargs):
    # do something else, don't care about the args
        print 'myfoo'
        super(MyFoo, self).__init__(*args, **kwargs)

I tried some things on this example and running the code this way:

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

I got this:

[...]
    super(MyFoo, self).__init__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'stack'

Changing to be like super(MyFoo, self).__init__(args, kwargs)

the results are:

('Python', 2.7) {'stack': 'overflow'}
I think something is being called here
('Python', 2.7) {'stack': 'overflow'}

For some blow mind reasons I'm questioning this: what could be right and wrong in the example above? What would be allowed to do and what wouldn't in real life production?

like image 723
Nice Guy Avatar asked Feb 09 '14 15:02

Nice Guy


People also ask

Can you have Kwargs without args?

Python is pretty flexible in terms of how arguments are passed to a function. The *args and **kwargs make it easier and cleaner to handle arguments. The important parts are “*” and “**”. You can use any word instead of args and kwargs but it is the common practice to use the words args and kwargs.

How do you pass things in Kwargs?

Kwargs allow you to pass keyword arguments to a function. They are used when you are not sure of the number of keyword arguments that will be passed in the function. Kwargs can be used for unpacking dictionary key, value pairs. This is done using the double asterisk notation ( ** ).

Why is Kwargs empty?

That dictionary is empty because you have not passed any kwargs in foo1. Note that you should only use variable x and y. Any other variables will cause error.

How does args and Kwargs work in Python?

The *args and **kwargs keywords allow you to pass a variable number of arguments to a Python function. The *args keyword sends a list of values to a function. **kwargs sends a dictionary with values associated with keywords to a function. Both of these keywords introduce more flexibility into your code.


2 Answers

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.

like image 124
Martijn Pieters Avatar answered Oct 19 '22 04:10

Martijn Pieters


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

like image 8
Bryan Oakley Avatar answered Oct 19 '22 03:10

Bryan Oakley