[Python-3000] The 'make' statement PEP (was Re: Did I miss anything?)

Nick Coghlan ncoghlan at gmail.com
Tue Apr 11 13:42:41 CEST 2006


Steven Bethard wrote:
> This is potentially a Python 2.6 PEP, but it has some optional
> extensions for Python 3000 and may be relevant to the
> adaptation/overloading/interfaces discussion.  It proposes a make
> statement such that:
>     make <callable> <name> <tuple>:
>         <block>
> would be translated into the assignment:
>     <name> = <callable>("<name>", <tuple>, <namespace>)
> much in the same way that the class statement works.  I've posted it
> to comp.lang.python and had generally positive feedback.  I've
> submitted it for a PEP number, but I haven't heard back yet:
> 
> http://ucsu.colorado.edu/~bethard/py/pep_make_statement.txt
> http://ucsu.colorado.edu/~bethard/py/pep_make_statement.html

Pretty nice, but I think it would be even better if instead of focusing on the
rare use case of a callable that needs to know the name it is being bound to,
we looked at the more general idea of "use a trailing suite to define the
keyword arguments to a function".

And rather than a new keyword, I'd suggest permitting a "**" without a
following expression to denote 'fill in these keyword arguments based on the
following suite'. This would be permitted in simple statements only (so 
there's no other suite to get in the way), with all occurrences being passed 
the namespace of the following suite as the keyword dictionary.

Cases that wanted the callable to know the name would still need to pass it in
explicitly as a string, but the upside of the tradeoff is that all existing
callables that take keyword arguments would *just work* with the new syntax. 
(Also see the ElementTree example at the end for the case where not being able 
to provide the name explicitly would be a big problem).

# Populate a switch dictionary
options = dict(**):
     def option1(*args, **kwds):
         # Do option 1
     def option2(*args, **kwds):
         # Do option 2
     # etc. . .

# Define a property
class C(object):
     foo = property(**):
         doc = "The foo property"
         def fget(self):
             # Get foo
         def fset(self):
             # Set foo
         def fdel(self):
             # Delete foo

# Sort an iterable by an arbitrary key
results = sorted(result_gen, **):
     def key(item):
         return (item.kind, item.result[0])

I'd be perfectly happy to trade the need to occasionally repeat myself in the
rare cases where I'd want the callable to know the name for the benefit of a
syntax that let me push the keywords of an arbitrary callable into a
subordinate suite.

And here's a trick if you really wanted to be able to define an 'anonymous'
function:

def anon(**kwds):
     return kwds['anon']

result = widget.callback(anon(**)):
     def anon(*args, **kwds):
         # Define the callback for the widget


And to finish, an element tree example (based on the one on the front page of 
Effbot's overview, rather than the abbreviated one in the PEP). I think this 
example shows that requiring that an element's tag be the same as its name 
would in fact be a *bad* idea (how would you build the two paragraphs in the 
body?)

# The supporting act
import xml.etree.ElementTree as ET

def _make_element(tag, text, tail, namespace):
     """Build an XML element from a namespace"""
     element = ET.Element(tag)
     element.text = text
     element.tail = tail
     for name, value in namespace.iteritems():
         if isinstance(value, ET.Element):
             if value.tag is None:
                 value.tag = name
             element.append(value)
         else:
             element.set(name, value)


def element(tag=None, text=None, tail=None, **kwds):
     """Create a new element"""
     return _make_element(tag, text, tail, kwds)

def make_tree(tag, text=None, tail=None, **kwds):
     root = _make_element(tag, text, tail, kwds)
     return ET.ElementTree(root)

# The performance
tree = make_tree("html", **):
     head = element(**):
         title = element(**):
             text = "Page Title"

     body = element(**):
         bgcolor = "#ffffff"
         para1 = element("p", **):
             text = "Hello, World!"
         para2 = element("p", **):
             text = "And hello, again!"

# wrap it in an ElementTree instance, and save as XML
tree.write("page.xhtml")

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-3000 mailing list