Wizard
Wizard

Reputation: 22043

How to apply '*args' and '*kwargs' to define a `class`

For the ease of further scale, I define a class Book with args and 'kwargs'.

class Book:
    def __init__(self, *args, **kwargs):
        if args:
            self.name,\
            self.author,\
            = args
        elif kwargs:
            self.__dict__.update(kwargs)

It works well respectively with positional and keywords arguments

In [62]: book1 = Book('Python', 'Guido')
In [63]: book1.author
Out[63]: 'Guido'

In [65]: book2 = Book(name='Python', author='Guido')
In [66]: book2.name
Out[66]: 'Python'

When test with mixture of positional and keywords arguments,error reports.

In [67]: book3 = Book('Python', author='Guido')
ValueError: not enough values to unpack (expected 2, got 1)

The bug can be fixed with multiple conditions or a standard definition class without taking *args or 'kwargs'.

How to fix it in an elegant method?

Upvotes: 0

Views: 4005

Answers (3)

Sharad
Sharad

Reputation: 10592

I'd advise against just args and kwargs. But just in case you absolutely need it, here's one way:

class Book:
    def __init__(self, *args, **kwargs):
       attributes = ['name', 'author']
       for item in zip(attributes, args):
           kwargs[item[0]] = item[1]
       self.name = kwargs.get('name')
       self.author = kwargs.get('author')

    def show(self):
        print('Name={name}, author={author}'.format(name=self.name, author=self.author))

book1 = Book('Python', 'Guido')
book1.show()
book2 = Book(name='Python', author='Guido')
book2.show()
book3 = Book('Python', author='Guido')

Execution output:

Name=Python, author=Guido
Name=Python, author=Guido
Name=Python, author=Guido

Upvotes: 1

SethMMorton
SethMMorton

Reputation: 48725

I would advise against *args and **kwargs here, since the way you wish to use them is not they way they were intended to be used. Just use named arguments and you will be able to do all that you want.

class Book:
    def __init__(self, name, author):
        self.name = name
        self.author = author

Works as expected.

In [2]: book1 = Book('Python', 'Guido')

In [3]: book2 = Book(name='Python', author='Guido')

In [4]: book3 = Book('Python', author='Guido')

In [7]: book1.name == book2.name
Out[7]: True

In [8]: book1.name == book3.name
Out[8]: True

In [9]: book2.name == book3.name
Out[9]: True

Upvotes: 2

bow
bow

Reputation: 2563

If your goal is to accept optional name and author arguments, you should use default arguments:

class Book(object):

    def __init__(self, name=None, author=None):
        self.name = name
        self.author = author

Not only does this make the class definition simpler, it also conveys better intent in the __init__ signature:

>>> c = Book("best book", "me")
>>> c.name
'best book'
>>> c.author
'me'
>>> c = Book(author="me", name="best book")
>>> c.name
'best book'
>>> c.author
'me'
>>> c = Book("best_book", author="me")
>>> c.name
'best book'
>>> c.author
'me'

Upvotes: 3

Related Questions