[Python-ideas] @partials = decorators

Alex Rodrigues lemiant at hotmail.com
Mon Feb 10 20:44:38 CET 2014


This is a really cool idea. I'm +1. The first time I learned about decorators the way that you pass them arguments was both very non-intuitive and seemed almost like a sneaky hack rather than an intended feature.

# In my opinion this is more intuitive than the old way
def annotate(msg, foo, *arg, **kwargs):
    print msg
    foo(*arg, **kwargs)

@annotate("Addition")
    def func(a, b):
        print a + b

#The old way
def annotate(msg):
    def deco(foo):
        def wrapper(*args, **kwargs):
            print msg
            foo(*args, **kwargs)
        return wrapper
    return deco

@annotate("Addition")
def func(a, b):
    print a + b


(Ironically I had a really hard time getting the "old" one put together correctly). This also very effectively simplifies a lot of closure cases. There is one thing I don't quite understand, is it necessary to explicitly state that some function is a continuation each time you add arguments? As I understand it, that would mean decorators with arguments have to be called by  "@@deco(a, b)".

This would actually help me out in a real world example at this very moment, which is currently really, really hard to do cleanly. I am using iPython notebook and I'm creating two histograms like so:

#data is a pandas Series() objects
data.hist()
data.hist(log=True)

In the notebook these are both reasonably skinny graphs but they stack on top of each other instead of side by side. I looked it up and that can be fixed like so:

fig = plt.figure()
ax1 = plt.subplot(121)
ax2 = plt.subplot(122)
data.hist(ax=ax1)
data.hist(ax=ax2, log=True)

This is pretty cumbersome to write out every time so I wanted a function that could just be called on arbitrary histograms like side_by_side(data1.hist(bottom=0.1, log=True), data2.hist(bins=10)). The problem is that I do not have the axes available when I call the function and once I pass the plots to the function they have already been evaluated and there is no way to add arguments retroactively. With the continuation syntax it would be amazingly easier:

def side_by_side(plot1, plot2):
    fig = plt.figure()
    ax1 = plt.subplot(121)
    ax2 = plt.subplot(122)
    plot1(ax=ax1)
    plot2(ax=ax2)

side_by_side(@data.hist(), @data.hist(log=True)) #Technically the first one doesn't need to be a continuation, but whatever.

tldr; I like it and see a decent number of applications. Also I'm  wondering if you'd have to chain continuations @@a('arg1')('arg2')('arg3').

- Alex 		 	   		  


More information about the Python-ideas mailing list