Pondering 42 in Finite States

Yet another blog, by yet another person.

Random stuff about Python, Java, Scala, and other random stuff.

2008-03-01

Goodbye apply()

apply() is Going Away

Python 3.0 will remove apply() from built-ins. What follows is a farewell party for apply().

Python Functions

Consider the following Python example:

def eat(staple, *sides, **drinks):
   pass

def find(thing, tool="camera", bait=None):
   pass

# Now we can call eat as follows:
eat("omelette", "fries", "crisps", start="soda", end="wine")

# And find as follows:
find("rat", bait="cheese")

Passing Arguments from Iterables and Dictionaries

What if we had an iterable and a dictionary with the values that need to be passed for sides and drinks, respectively? We could pick out each element and write out the whole function call. That wouldn't really work for variable length arguments, and dictionaries which are essentially optional key-value pairs.

The original solution was the apply() built-in, which was just a function to invoke a function with arguments given by an iterable and an optional dictionary.

Using apply()

There used to be a time, when the only non-ugly way of doing this would be to use the built-in apply() as follows:

apply(eat, food_and_sides_iter, drinks_dict) 

Furthermore, we had to combine the variable length sides with the initial arguments. If these were not together, we will need to combine them.

apply(eat, ("omelette",) + tuple(sides_iter), drinks_dict)

Language Integration of the apply() Feature

This apply feature is so handy, that language support for this feature was added. So, apply() was not really removed, it was made part of the core language. This means that, instead of using the built-in function apply() , we simply indicate that our iterable or dictionary should be unpacked.

Our earlier examples become:

eat(*food_and_sides_iter, **drinks_dict)
# and
eat("omelette", *sides_iter, **drinks_dict)

# even
eat("omelette", special_side, *sides_iter, **drinks_dict)

# just one side? just put it there
eat("omelette", just_fries, **drinks_dict)

# no sides? no problem
eat("omelette", **drinks_dict)
# no iters or dicts
eat("omelette", "fries", "pesto", start="water", end="KCN")

# even for without variable arity
find("rat", **tool_kit_dict)

As you can see, the integrated feature is much more flexible, and cleaner. You don't need to manually pack and unpack things (which is needed in some cases with the apply() built-in).

No More Auto-unpacking of Tuples

With the apply feature entrenched int the core Python language for years, and the redundant apply removed, another small clean-up was in order. Tuples will no longer be automatically unpacked in function calls.

# This won't work any more (in 3.0)
eat("omelette", sides_tuple)

# Need to do this 
eat("omelette", *sides_tuple)

This is to keep the syntax regular--removing special cases where possible (as noted in the Zen of Python):

Special cases aren't special enough to break the rules.
Although practicality beats purity.

The Spirit of apply() Lives On

I am not sure now, if calling this a farewell party for apply() is accurate. We could view this as a welcoming party, where apply() is now in the core language and no longer standing outside as well, just in case. There is a problem with this as well, because apply feature was integrated into the language a long-long time ago. Maybe, we can call this the official induction. :-)

All that is gone is the built-in function apply(), not the feature, which is already integrated into the language.

Labels: , ,

This page is powered by Blogger. Isn't yours?

Feeds

Subscribe to
Posts [Atom]

Bookmarks

Previous Posts

Archives

   2004-05     2004-06     2004-11     2005-04     2005-05     2005-06     2005-10     2006-10     2007-02     2007-03     2007-04     2007-12     2008-03     2008-06     2008-07     2008-09     2008-10     2009-07     2010-07 
© 2004-2009 FiniteState42i (yahoo.com ID: finitestate42i)