E-Scribe : a programmer’s blog

About Me

PBX I'm Paul Bissex. I build web applications using open source software, especially Django. Started my career doing graphic design for newspapers and magazines in the '90s. Then wrote tech commentary and reviews for Wired, Salon, Chicago Tribune, and others you never heard of. Then I built operations software at a photography school. Then I helped big media serve 40 million pages a day. Then I worked on a translation services API doing millions of dollars of business. Now I'm building the core platform of a global startup accelerator. Feel free to email me.

Book

I co-wrote "Python Web Development with Django". It was the first book to cover the long-awaited Django 1.0. Published by Addison-Wesley and still in print!

Colophon

Built using Django, served with gunicorn and nginx. The database is SQLite. Hosted on a FreeBSD VPS at Johncompanies.com. Comment-spam protection by Akismet.

Pile o'Tags

Stuff I Use

bitbucket, Django, Emacs, FreeBSD, Git, jQuery, LaunchBar, Markdown, Mercurial, OS X, Python, Review Board, S3, SQLite, Sublime Text, Ubuntu Linux

Spam Report

At least 236525 pieces of comment spam killed since 2008, mostly via Akismet.

Neat Python hack: infix operators

I came across this neat Python hack on reddit today, a technique for defining arbitrary infix operators. Not overriding + or >> et al., but creating keyword-style pseudo-operators that... well, the code is probably as clear as any description I could come up with:

class infix(object):
    """
    Clever hack (slightly modified) for defining infix operators. 
    Via http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122
    Intended for use as a decorator.

    >>> @infix
    ... def removing(str, chars):
    ...     for char in chars:
    ...         str = str.replace(char, '')
    ...     return str
    ...
    >>> print 'Hello, world!' |removing| 'eo'
    Hll, wrld!
    """
    def __init__(self, function):
        self.function = function
    def __ror__(self, other):
        return infix(lambda x: self.function(other, x))
    def __or__(self, other):
        return self.function(other)
    def __call__(self, value1, value2):
        return self.function(value1, value2)

Some people hate this kind of stuff. That's why we call it a hack, to indicate that we don't think it's a great building block for your missile control software. Some of Those People still get their underoos in a bunch regardless. But you have to admit it's damned clever.

This also reminds me of some of the lovely higher-order-function features in Haskell, where you can make a regular (prefix) function into infix by wrapping it in backticks -- 10 `mod` 3 -- and an infix function (operator) into prefix by wrapping it in parentheses -- (+) 2 2.

Sunday, February 25th, 2007
+ + +
7 comments

Comment from Justin , later that day

I totally hate it. :)

Comment from James , 4 days later

I totally love it. :)

Comment from Paul , 1 week later

Now that's what I call fair and balanced.

Comment from bruce , 14 months later

class infix2(object):
    def __init__(self, function):
        self.function = function
    def __ror__(self, other):
        self.value=other
        return self
    def __or__(self, other):
        return self.function(self.value,other)

With this version, you do not instanciate a lambda object for each __ror__ call. On my PC, it's 45% performance gain !

Comment from Paul , 14 months later

I love that you profiled it.

Comment from Lionel , 4 years later

What about this one http://pypi.python.org/pypi/pipe/1.3 ? It's simplier and have ~30 already implemented infix operators

Comment from Nicko , 4 years later

Bruce, the problem with your solution is that it only has one place to store the left-hand value, so it fails if more than one operation is in flight at a time:

plus = infix2(lambda x,y:x+y) 1 |plus| 2 |plus| 3 6 1 |plus| (2 |plus| 3) 7

Comments are closed for this post. But I welcome questions/comments via email or Twitter.