Book Excerpt: The Python Standard Library by Example
Under Python 2, classes can define a __cmp__() method that returns -1, 0, or 1 based on whether the object is less than, equal to, or greater than the item being compared. Python 2.1 introduces the rich comparison methods API (__lt__(), __le__(), __eq__(), __ne__(), __gt__(), and __ge__()), which perform a single comparison operation and return a Boolean value. Python 3 deprecated __cmp__() in favor of these new methods, so functools provides tools to make it easier to write Python 2 classes that comply with the new comparison requirements in Python 3.
The rich comparison API is designed to allow classes with complex comparisons to implement each test in the most efficient way possible. However, for classes where comparison is relatively simple, there is no point in manually creating each of the rich comparison methods. The total_ordering() class decorator takes a class that provides some of the methods and adds the rest of them.
import functools import inspect from pprint import pprint @functools.total_ordering class MyObject(object): def __init__(self, val): self.val = val def __eq__(self, other): print ’ testing __eq__(%s, %s)’ % (self.val, other.val) return self.val == other.val def __gt__(self, other): print ’ testing __gt__(%s, %s)’ % (self.val, other.val) return self.val > other.val print ’Methods:\n’ pprint(inspect.getmembers(MyObject, inspect.ismethod)) a = MyObject(1) b = MyObject(2) print ’\nComparisons:’ for expr in [ ’a < b’, ’a <= b’, ’a == b’, ’a >= b’, ’a > b’ ]: print ’\n%-6s:’ % expr result = eval(expr) print ’ result of %s: <%s’ % (expr, result)
The class must provide implementation of __eq__() and one other rich comparison method. The decorator adds implementations of the rest of the methods that work by using the comparisons provided.
$ python functools_total_ordering.py Methods: [(’__eq__’, <unbound method MyObject.__eq__>), (’__ge__’, <unbound method MyObject.__ge__>), (’__gt__’, <unbound method MyObject.__gt__>), (’__init__’, <unbound method MyObject.__init__>), (’__le__’, <unbound method MyObject.__le__>), (’__lt__’, <unbound method MyObject.__lt__>)] Comparisons: a < b: testing __gt__(2, 1) result of a < b: True a <= b: testing __gt__(1, 2) result of a <= b: True a == b: testing __eq__(1, 2) result of a == b: False a >= b: testing __gt__(2, 1) result of a >= b: False a > b: testing __gt__(1, 2) result of a > b: False
Since old-style comparison functions are deprecated in Python 3, the cmp argument to functions like sort() is also no longer supported. Python 2 programs that use comparison functions can use cmp_to_key() to convert them to a function that returns a collation key, which is used to determine the position in the final sequence.
import functools class MyObject(object): def __init__(self, val): self.val = val def __str__(self): return ’MyObject(%s)’ % self.val def compare_obj(a, b): """Old-style comparison function. """ print ’comparing %s and %s’ % (a, b) return cmp(a.val, b.val) # Make a key function using cmp_to_key() get_key = functools.cmp_to_key(compare_obj) def get_key_wrapper(o): """Wrapper function for get_key to allow for print statements. """ new_key = get_key(o) print ’key_wrapper(%s) -> %s’ % (o, new_key) return new_key objs = [ MyObject(x) for x in xrange(5, 0, -1) ] for o in sorted(objs, key=get_key_wrapper): print o
Normally, cmp_to_key() would be used directly, but in this example, an extra wrapper function is introduced to print out more information as the key function is being called.
The output shows that sorted() starts by calling get_key_wrapper() for each item in the sequence to produce a key. The keys returned by cmp_to_key() are instances of a class defined in functools that implements the rich comparison API using the old-style comparison function passed in. After all keys are created, the sequence is sorted by comparing the keys.
$ python functools_cmp_to_key.py key_wrapper(MyObject(5)) -> <functools.K object at 0x100da2a50> key_wrapper(MyObject(4)) -> <functools.K object at 0x100da2a90> key_wrapper(MyObject(3)) -> <functools.K object at 0x100da2ad0> key_wrapper(MyObject(2)) -> <functools.K object at 0x100da2b10> key_wrapper(MyObject(1)) -> <functools.K object at 0x100da2b50> comparing MyObject(4) and MyObject(5) comparing MyObject(3) and MyObject(4) comparing MyObject(2) and MyObject(3) comparing MyObject(1) and MyObject(2) MyObject(1) MyObject(2) MyObject(3) MyObject(4) MyObject(5)
functools (http://docs.python.org/library/functools.html) The standard library documentation for this module.
Rich comparison methods (http://docs.python.org/reference/datamodel.html# object.__lt__) Description of the rich comparison methods from the Python Reference Guide.
inspect (page 1200) Introspection API for live objects.
© Copyright Pearson Education. All rights reserved.
Excerpt from Python Standard Library by Example, The.
|By Doug Hellmann
Published by Addison-Wesley Professional
This excerpt is from the book, ‘The Python Standard Library by Example’ by Doug Hellmann, published by Pearson/Addison-Wesley Professional, June 2011, ISBN 0321767349, Copyright 2011 Pearson Education, Inc. For more info please visit www.informit.com/title/0321767349
- The Tiny Internet Project, Part I
- Machine Learning with Python
- SUSECON 2016: Where Technology Reigns Supreme
- Download "Linux Management with Red Hat Satellite: Measuring Business Impact and ROI"
- Free Today: September Issue of Linux Journal (Retail value: $5.99)
- Bitcoin on Amazon! Sort of...
- Securing the Programmer
- Android Browser Security--What You Haven't Been Told
- Epiq Solutions' Sidekiq M.2
Pick up any e-commerce web or mobile app today, and you’ll be holding a mashup of interconnected applications and services from a variety of different providers. For instance, when you connect to Amazon’s e-commerce app, cookies, tags and pixels that are monitored by solutions like Exact Target, BazaarVoice, Bing, Shopzilla, Liveramp and Google Tag Manager track every action you take. You’re presented with special offers and coupons based on your viewing and buying patterns. If you find something you want for your birthday, a third party manages your wish list, which you can share through multiple social- media outlets or email to a friend. When you select something to buy, you find yourself presented with similar items as kind suggestions. And when you finally check out, you’re offered the ability to pay with promo codes, gifts cards, PayPal or a variety of credit cards.Get the Guide