Reputation: 3920
I have two classes A
and B(A)
. Their constructor accept the style
dictionary as a keyword argument.
For A
objects I want, by default, the string green
to be associated to style['color']
.
For B
objects color
defaults to red
.
I came up with this solution but find it rather clumsy. Is there a more elegant way to do this?
class A:
def __init__(self, **kwargs):
style = kwargs.pop('style', {})
if 'color' not in style:
style['color'] = 'green'
print(style)
class B(A):
def __init__(self, **kwargs):
style = kwargs.pop('style', {})
if 'color' not in style:
style['color'] = 'red'
super().__init__(style=style, **kwargs)
A() # {'color': 'green'}
B() # {'color': 'red'}
B(style={'color': 'blue'}) # {'color': 'blue'}
Upvotes: 1
Views: 247
Reputation: 5237
Try the following instead.
It introduces a helper method to the base class called default_kwarg
.
This can be called in both cases (superclass and subclass) to set the default value of the color
key.
This approach also enables the style
dict to contain other key/value pairs. I've added an extra example at the end that demonstrates this.
class A:
def default_kwarg(self, arg, default):
arg = arg.pop('style', {})
if 'color' not in arg:
arg['color'] = default
return arg
def __init__(self, **kwargs):
style = self.default_kwarg(kwargs, 'green')
print(style)
class B(A):
def __init__(self, **kwargs):
kwargs['style'] = self.default_kwarg(kwargs, 'red')
super().__init__(**kwargs)
A() # {'color': 'green'}
B() # {'color': 'red'}
B(style={'color': 'blue'}) # {'color': 'blue'}
B(style={'something': 'else'}) # {'something': 'else', 'color': 'red'}
You could also generalize this helper method quite easily to apply defaults to other keys in the dict.
Upvotes: 1
Reputation: 4365
This looks slightly cleaner but it still feels a bit hacky:
class A:
def __init__(self, **kwargs):
self.style = kwargs.get('style', {'color': 'green'})
print(self.style)
class B(A):
def __init__(self, **kwargs):
kwargs['style'] = kwargs.get('style', {'color': 'red'})
super().__init__(**kwargs)
A() # {'color': 'green'}
B() # {'color': 'red'}
B(style={'color': 'blue'})
If style
is actually self.style
which I'm assuming it is, you can relegate the assignment to the parent class since it will always get there with super()
anyway.
This assumes that aren't attempting to pull 'style'
from kwargs
afterwards. You shouldn't need to since it's already assigned to self.style
.
You probably noticed that it would also fail if you would pass in style
but not assign a 'color'
to it. If you're planning on doing this, you would probably be better off just setting color
as a default keyword argument.
class A:
def __init__(self, color='green', **kwargs):
self.style = kwargs.get('style', {'color': color})
self.style['color'] = self.style.get('color', color)
print(self.style)
class B(A):
def __init__(self, color='red', **kwargs):
kwargs['style'] = kwargs.get('style', {'color': color})
super().__init__(color=color, **kwargs)
A() # {'color': 'green'}
B() # {'color': 'red'}
B(style={'font': 'Times New Roman'}) # {'color': 'red'}
B(style={'color': 'blue'})
Upvotes: 1