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.
OOP way to implement class for comparison in Python
-
31-03-2022 - |
Question
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
La solution
Autres conseils
I guess you just need to check if any of the operands is a fuzzy type, no?
class Fuzzy(object):
def __eq__(*args):
def isFuzzy(obj):
return isinstance(obj, Fuzzy)
return any(map(isFuzzy, args))
Now you can do:
>>> class DefaultClass(object):
... pass
>>> class DontCareClass(Fuzzy):
... pass
>>> DefaultClass() == DontCareClass()
True
Since we're using isInstance
, this will work just fine with polymorphism. This is a perfectly legitimate use of isInstance
in my opinion. What you want to avoid is type checking when you can just rely on duck typing, but this is not one of those cases.
EDIT: Actually, for practical purposes, this would be perfectly fine too:
class Fuzzy(object):
def __eq__(*args):
return True