<div dir="ltr"><div>Hi Steve,</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 25, 2015 at 7:54 PM, Steven D'Aprano <span dir="ltr"><<a href="mailto:steve@pearwood.info" target="_blank">steve@pearwood.info</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Are you sure this actually works in practice?<br>
<br>
Since pipe() returns the result of calling the passed in function, not<br>
the dataframe, it seems to me that you can't actually chain this unless<br>
it's the last call in the chain. </blockquote><div><br></div><div>This is a good point. We're pretty sure it will work in practice, because many functions that take dataframes return other dataframes -- or other objects that will implement a .pipe() method. The prototypical use case is actually closer to:</div><div><br></div><div>df.pipe(reformat_my_data)</div><div><br></div><div>Plotting and saving data with method chaining is convenient, but usually as the terminal step in a data analysis flow. None of the existing pandas methods for plotting or exporting return a dataframe, and it doesn't seem to be much of an impediment to method chaining.</div><div><br></div><div>That said, we've also thought about adding a .tee() method for exactly this use case -- it's like pipe, but returns the original object instead of modifying it.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">What's the point of the redirection to __pipe_func__? Under what<br>
circumstances would somebody use __pipe_func__ instead of just passing a<br>
callable (a function or other object with __call__ method)? If you don't<br>
have a good use case for it, then "You Ain't Gonna Need It" applies.<br></blockquote><div><br></div><div>Our main use case was for APIs that can't accept a DataFrame as their first argument, but that naturally can be understood as modifying dataframes.</div><div><br></div><div>Here's an example based on the Seaborn plotting library:</div><div><br></div><div>def scatterplot(x, y, data=None):</div><div>    # make a 2D plot of x vs y</div><div><br></div><div>If `x` or `y` are strings, Seaborn looks them up as columns in the provided dataframe `data`. But `x` and `y` can also be directly provided as columns. This API is in unfortunate conflict with passing in `data` as the first, required argument.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I think that is completely unnecessary. (It also abuses a reserved<br>
namespace, but you've already said you don't care about that.) Instead<br>
of passing:<br>
<br>
    .pipe(myobject, args)  # myobject has a __pipe_func__ method<br>
<br>
just make it explicit and write:<br>
<br>
    .pipe(myobject.some_method, args)<br></blockquote><div><br></div><div>This is a fair point. Writing something like:</div><div><br></div><div>.pipe(seaborn.scatterplot.df, 'x', 'y')</div><div><br></div><div>is not so much worst than omitting the .df.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Yes. I love chaining in, say, bash, and it works well in Ruby, but it's<br>
less useful in Python. My attempt to help bring chaining to Python is<br>
here<br>
<br>
<a href="http://code.activestate.com/recipes/578770-method-chaining/" target="_blank">http://code.activestate.com/recipes/578770-method-chaining/</a><br>
<br>
but it relies on methods operating by side-effect, not returning a new<br>
result. But generally speaking, I don't like methods that operate by<br>
side-effect, so I don't use chaining much in practice. I'm always on the<br>
look-out for opportunities where it makes sense though.<span class=""><br></span></blockquote><div><br></div><div>I think this is where we have an advantage in the PyData world. We tend to work less with built-in data structures and prefer to make our methods pure functions, which together make chaining much more feasible.</div><div><br></div><div>Cheers,</div><div>Stephan</div></div></div></div>