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
Était-ce utile?

La 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.

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top