开发者

What is the Python equivalent of Comparables in Java?

I have a dictionary of the following form:

{ <Category('Simulate', 'False', 'False', 'False', 'INTERMEDIATE')>: {'link': u'/story/4/tvb-adapters-simulator-simulatorAdapter/SimulatorAdapter', 'name': u'Simulate'}, 
  <Category('View Results', 'True', 'False', 'True', 'INTERMEDIATE')>: {'link': '/story/step/3', 'name': 开发者_如何学Cu'View Results'}, 
  <Category('Analyze', 'True', 'False', 'False', 'FINAL')>: {'link': '/story/step/2', 'name': u'Analyze'}}

Category is a class representing an instance from a database. Now I have the following instance:

    <Category('Analyze', 'True', 'False', 'False', 'FINAL')>

Now this is not the same instance. By this I mean, I get all the values from the database and create the dictionary. Then after a while I get an id and retrieve the instance from the database. Now they are not the same objects. I now have to check if it's in the dictionary, but:

instance in disctionary

Will return false. Now I could go the ugly way and iterate over the dictionary checking if all the values match, however does Python have a more clever way to do this? I mean something like the equivalent of Comparable in Java?


First: use True and False (boolean properties) instead of 'True' and 'False' (string properties).

Generally, you can make everything comparable in Python. You just have to define specific methods (like __eq__, __lt__, etc.) for your class.

So, let's say I want to compare instances of class A, and the comparison should be just case-insensitive string comparison of s member:

class A(object):
    def __init__(self, s=''):
        self.s = s

    def __eq__(self, other):
        return self.s.lower() == other.s.lower()

a = A('aaaa')
b = A('AAAA')
print a == b # prints True
b = A('bbbb')
print a == b # prints False


Instead of using instances of Category (e.g. Category('Analyze', 'True', 'False', 'False', 'FINAL')) as the keys in your dictionary, it sounds like you should be using the associated tuple (e.g. ('Analyze', 'True', 'False', 'False', 'FINAL')).

If you really do want to use instance of Category as the keys in the dictionary, you'll need to define both the __hash__ and __eq__ methods. For example:

class Category(object):
    def __init__(self,*args):
        self.args=args
    def __hash__(self):
        # Note that this assumes that Category's hash value is immutable
        # i.e. self.args does not change.
        return hash(self.args)
    def __eq__(self,other):
        return self.args == other.args

a=Category('Analyze', 'True', 'False', 'False', 'FINAL')
b=Category('Analyze', 'True', 'False', 'False', 'FINAL')

mydict={a:1}

a and b are distinct instances, so they have different ids, but their hash values are the same:

assert id(a) != id(b)
assert hash(a)==hash(b)

This shows b is an acceptable key in mydict:

print(mydict[a])
# 1
print(mydict[b])
# 1

PS. Don't bother with __cmp__. In Python 3:

The cmp() function should be treated as gone, and the __cmp__() special method is no longer supported. Use __lt__() for sorting, __eq__() with __hash__(), and other rich comparisons as needed.


As you can apparently put your category instances into a dict, you must have overwritten __hash__ already. All you need now is __eq__:

class Category(object):
    # you must have overwritten `__hash__` like this already
    def __hash__(self):
        return hash((self.attr1, self.attr2, ... ))

    # now you just need tis
    def __eq__(self, other):
        return isinstance(other, Category) and \
               (self.attr1, self.attr2, ... ) == (other.attr1, other.attr2, ... )

What you should really do is throw that whole class away and use a collections.namedtuple instead:

Category = collections.namedtuple('Category', 'attr1 attr2 attr3')


There could be shortcuts, like using tuples, but the generic answer to your question is: implement __eq__() for your class, so that cmp() will use it instead of testing for identity.


For in and other comparison operators to work, you have to implement __hash__ and __cmp__ (or the "rich" comparison methods like __eq__). See the Python reference.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜