Hướng dẫn python comparable object
For a full set of comparison functions I have used the following mixin, which you could put in say for example a mixin.py in your module.
To use the mixin above you need to implement a _cmpkey() method that returns a key of objects that can be compared, similar to the key() function used when sorting. The implementation could look like this:
The reason I use this instead of the total_ordering recipe is this bug. It's fixed in Python 3.4, but often you need to support older Python versions as well. Python 3 is strict when comparing objects of disparate types. It also drops cmp-based comparison and sorting in favor of rich comparisons and key-based sorting, modern alternatives that have been available at least since Python 2.4. Details and porting strategies follow. Unorderable Types¶The strict approach to comparing in Python 3 makes it generally impossible to compare different types of objects. For example, in Python 2, comparing but in Python 3, it fails with a well described error message: >>> 2 < '2' Traceback (most recent call last): File " The change usually manifests itself in sorting lists: in Python 3, lists with items of different types are generally not sortable. If you need to sort heterogeneous lists, or compare different types of objects, implement a key function to fully describe how disparate types should be ordered. Rich Comparisons¶
The In Python 2, This approach of representing comparison results is common in C-style languages. But, early in Python 2 development, it became apparent that only allowing three cases for the relative order of objects is too limiting. This led to the introduction of rich comparison methods, which assign a special method to each operator:
Each takes the same two arguments as cmp, and must return either a result value (typically Boolean), raise an exception, or return In Python 3, the cmp style of comparisons was dropped. All objects that implemented To avoid the hassle of providing all six functions, you can implement The As an example, suppose that you have a class to represent a person with class Person(object): def __init__(self, firstname, lastname): self.first = firstname self.last = lastname def __cmp__(self, other): return cmp((self.last, self.first), (other.last, other.first)) def __repr__(self): return "%s %s" % (self.first, self.last) With from functools import total_ordering @total_ordering class Person(object): def __init__(self, firstname, lastname): self.first = firstname self.last = lastname def __eq__(self, other): return ((self.last, self.first) == (other.last, other.first)) def __ne__(self, other): return not (self == other) def __lt__(self, other): return ((self.last, self.first) < (other.last, other.first)) def __repr__(self): return "%s %s" % (self.first, self.last) If class Person(object): def __init__(self, firstname, lastname): self.first = firstname self.last = lastname def __eq__(self, other): return ((self.last, self.first) == (other.last, other.first)) def __ne__(self, other): return ((self.last, self.first) != (other.last, other.first)) def __lt__(self, other): return ((self.last, self.first) < (other.last, other.first)) def __le__(self, other): return ((self.last, self.first) <= (other.last, other.first)) def __gt__(self, other): return ((self.last, self.first) > (other.last, other.first)) def __ge__(self, other): return ((self.last, self.first) >= (other.last, other.first)) def __repr__(self): return "%s %s" % (self.first, self.last) The cmp Function¶
As part of the move away from cmp-style comparisons, the If it is necessary (usually to conform to an external API), you can provide it with this code: def cmp(x, y): """ Replacement for built-in function cmp that was removed in Python 3 Compare the two objects x and y and return an integer according to the outcome. The return value is negative if x < y, zero if x == y and strictly positive if x > y. """ return (x > y) - (x < y) The expression used is not straightforward, so if you need the functionality, we recommend adding the full, documented function to your project’s utility library. The cmp Argument¶
In Python 2, For example, given a list of instances of a Person class (defined above): >>> actors = [Person('Eric', 'Idle'), ... Person('John', 'Cleese'), ... Person('Michael', 'Palin'), ... Person('Terry', 'Gilliam'), ... Person('Terry', 'Jones')] ... one way to sort it by last name in Python 2 would be: >>> def cmp_last_name(a, b): ... """ Compare names by last name""" ... return cmp(a.last, b.last) ... >>> sorted(actors, cmp=cmp_last_name) ['John Cleese', 'Terry Gilliam', 'Eric Idle', 'Terry Jones', 'Michael Palin'] This function is called many times – O(n log n) – during the comparison. As an alternative to cmp, sorting functions can take a keyword-only >>> def keyfunction(item): ... """Key for comparison by last name""" ... return item.last ... >>> sorted(actors, key=keyfunction) ['John Cleese', 'Terry Gilliam', 'Eric Idle', 'Terry Jones', 'Michael Palin'] The advantage of this approach is that this function is called only once for each item. When simple types such as tuples, strings, and numbers are used for keys, the many comparisons are then handled by optimized C code. Also, in most cases key functions are more readable than cmp: usually, people think of sorting by some aspect of an object (such as last name), rather than by comparing individual objects. The main disadvantage is that the old cmp style is commonly used in C-language APIs, so external libraries are likely to provide similar functions. In Python 3, the There is no fixer for this change. However, discovering it is straightforward: the calling
|