Search code examples
pythonmatchingreadability

OOP way to implement class for comparison in Python


Using Python, I am trying to implement a set of types including a "don't care" type, for fuzzy matching. I have implemented it like so:

class Matchable(object):        
    def __init__(self, match_type = 'DEFAULT'):
        self.match_type = match_type

    def __eq__(self, other):
        return (self.match_type == 'DONTCARE' or other.match_type == 'DONTCARE' \
or self.match_type == other.match_type)

Coming from an OO background, this solution seems inelegant; using the Matchable class results in ugly code. I'd prefer to eliminate match_type, and instead make each type its own class inherited from a superclass, then use type checking to do the comparisons. However type checking appears to be generally frowned upon:

http://www.canonical.org/~kragen/isinstance/

Is there are better (more pythonic) way to implement this functionality?

Note: I'm aware of the large number of questions and answers about Python "enums", and it may be that one of those answers is appropriate. The requirement for the overridden __ eq __ function complicates matters, and I haven't seen a way to use the proposed enum implementations for this case.

The best OO way I can come up with of doing this is:

class Match(object):
    def __eq__(self, other):
        return isinstance(self, DontCare) or isinstance(other, DontCare) or type(self) == type(other)

class DontCare(Match):
    pass

class A(Match):
    pass

class B(Match):
    pass

d = DontCare()
a = A()
b = B()


print d == a
True
print a == d
True
print d == b
True
print a == b
False
print d == 1
True
print a == 1
False

Solution

  • The article you linked says that isinstance isn't always evil, and I think in your case it is appropriate. The main complaint in the article is that using isinstance to check whether an object supports a particular interface reduces opportunities to use implied interfaces, and it's a fair point. In your case, however, you would essentially be using a Dontcare class to provide an annotation for how an object should be treated in comparisons, and isinstance would be checking such an annotation, which should be perfectly. fine.