Refactoring similar subclasses

S

Steven D'Aprano

I have some code that currently takes four different classes, A, B, C and
D, and subclasses each of them in the same way:

class MyA(A):
def method(self, x):
result = super(MyA, self).method(x)
if result == "spam":
return "spam spam spam"
return result
# many more methods overloaded


class MyB(B):
def method(self, x):
result = super(MyB, self).method(x)
if result == "spam":
return "spam spam spam"
return result
# many more methods overloaded


and so on, for MyC and MyD. There's a lot of duplicated code in there.
What techniques do you suggest for reducing the code duplication? I
thought about some variation of:

names = "MyA MyB MyC MyD".split()
bases = [A, B, C, D]
d = dict-of-overloaded-methods
for name, base in zip(names, bases):
globals()[name] = type(name, [base], d)


but I'm not sure that this is a good approach, or how to inject the right
arguments to super in the dict.

Any suggestions or guidelines?
 
P

Peter Otten

Steven said:
I have some code that currently takes four different classes, A, B, C and
D, and subclasses each of them in the same way:

class MyA(A):
def method(self, x):
result = super(MyA, self).method(x)
if result == "spam":
return "spam spam spam"
return result
# many more methods overloaded


class MyB(B):
def method(self, x):
result = super(MyB, self).method(x)
if result == "spam":
return "spam spam spam"
return result
# many more methods overloaded


and so on, for MyC and MyD. There's a lot of duplicated code in there.
What techniques do you suggest for reducing the code duplication? I
thought about some variation of:

names = "MyA MyB MyC MyD".split()
bases = [A, B, C, D]
d = dict-of-overloaded-methods
for name, base in zip(names, bases):
globals()[name] = type(name, [base], d)


but I'm not sure that this is a good approach, or how to inject the right
arguments to super in the dict.

Any suggestions or guidelines?

You could use a mixin:

class Mixin(object):
def method(self, x):
result = super(Mixin, self).method(x)
if result == "spam":
return "spam spam spam"
return result

# ...

for name, base in zip(names, bases):
globals()[name] = type(name, (Mixin, base), {})

Peter
 
S

Steven D'Aprano

Steven said:
I have some code that currently takes four different classes, A, B, C
and D, and subclasses each of them in the same way: [...]
Any suggestions or guidelines?

You could use a mixin:

Nice! I'll give it a try. I knew that sooner or later I'd find a reason
for mixins :)
 
B

Bruno Desthuilliers

Steven D'Aprano a écrit :
I have some code that currently takes four different classes, A, B, C and
D, and subclasses each of them in the same way:

class MyA(A):
def method(self, x):
result = super(MyA, self).method(x)
if result == "spam":
return "spam spam spam"
return result
# many more methods overloaded


class MyB(B):
def method(self, x):
result = super(MyB, self).method(x)
if result == "spam":
return "spam spam spam"
return result
# many more methods overloaded

If that's really what your code is doing - I mean, calling the super()
implementation, checking the result and eventually returning something
else instead - then a simple decorator might be enough... Could even be
"applied" by the metaclass.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top