Reputation: 22043
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
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
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
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