I have some Python classes that, if simplified, look like:
class base:
def __init__(self, v):
self.value = v
def doThings(self):
print "Doing things."
def doMoreThings(self):
print "Doing more things."
def combine(self, b):
self.value += b.value
class foo(base):
def showValue(self):
print "foo value is %d." % self.value
class bar(base):
def showValue(self):
print "bar value is %d." % self.value
The base
class contains methods (represented above by doThings
and doMoreThings
) which implement functionality common to both the foo
and bar
subclasses. The foo
and bar
subclasses differ essentially in how they interpret the value
field. (Above, they only differ by what they show when printing it, but in my actual application, they do several other things which are more complicated.) base
can be thought of as "abstract": users only ever work with foo
s and bar
s. base
exists only as a home for code common to its subclasses.
The method I want to ask about is combine
, which lets you take two of these objects and make a third. Because foo
and bar
interpret value
differently, it doesn't make sense to combine
two subclasses of different types: you can combine
two foo
s to get a foo
or two bar
s to get a bar
but not a foo
and a bar
. Even so, the procedure for combine
is the same for all subclasses, so it makes sense to have it factored out and defined in one place.
I would probably like to signal an error if a user tries to combine
two incompatible objects, but I don't see a way to do this without introducing ugly typechecks. Is it good practice to do this? Or should I do the usual thing and not check, document the issue, and assume that the user won't try to use combine
in a way that wasn't intended, even though such use would appear to "succeed" and return a garbage object instead of raising an error?
Thank you for your help.
I see several approaches here:
Don't check anything and trust the user to do the right thing. Might be appropriate or dangerous, depending on the situation.
Check the type. You are right that it looks ugly, but is the easiest thing.
Don't have a value
, but name them the way they are intended to have (pressure
, temperature
) and let them combine themselves.
Same as 3, but additionally have the subclasses have a property
which maps accesses to .value
to their respective "real" value variable. This way, you can keep the .__init__()
, but the .combine()
will have to be done by every subclass.
Same as 4, but don't use property
, but a self-crafted descriptor. In this answer, I show how it could be done.
Alter the combine method
def combine(self, b):
if (not(self.__class__.__name__ == b.__class__.__name__)):
raise TypeError("%s cannot combine with %s" % ( self.__class__.__name__, b.__class__.__name__))
else:
self.value += b.value
Alternatively, alter the class definition for base to
class base(object):
and then a simpler, nicer, happier combine method is possible (thanks glglgl)
def combine(self, b):
if (not(type(self) == type(b))):
raise TypeError("%s cannot combine with %s" %
( type(self), type(b) ))
else:
self.value += b.value
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With