updated pre-PEP: The create statement

Steven Bethard steven.bethard at gmail.com
Thu Apr 6 12:36:39 EDT 2006


Steven Bethard wrote:
> I've updated the PEP based on a number of comments on comp.lang.python. 
> The most updated versions are still at:
> 
>     http://ucsu.colorado.edu/~bethard/py/pep_create_statement.txt
>     http://ucsu.colorado.edu/~bethard/py/pep_create_statement.html
> 
> In this post, I'm especially soliciting review of Carl Banks's point 
> (now discussed under Open Issues) which asks if it would be better to 
> have the create statement translated into:
> 
>     <name> = <callable>("<name>", *<tuple>, **<namespace>)
> 
> instead of the current:
> 
>     <name> = <callable>("<name>", <tuple>, <namespace>)
> 
> The former allows the create statement to be applied to a wider variety 
> of callables; the latter keeps a better parallel with the class statement.

Sorry, there were some errors in the copy of the PEP I posted with this 
message.  (The PEPs at the URLs above are correct though.)  Here is the 
corrected PEP:

PEP: XXX
Title: The create statement
Version: $Revision: 1.4 $
Last-Modified: $Date: 2003/09/22 04:51:50 $
Author: Steven Bethard <steven.bethard at gmail.com>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 05-Apr-2006
Python-Version: 2.6
Post-History: 05-Apr-2006, 06-Apr-2006


Abstract
========

This PEP proposes a generalization of the class-declaration syntax,
the ``create`` statement. The proposed syntax and semantics parallel
the syntax for class definition, and so::

    create <callable> <name> <tuple>:
        <block>

is translated into the assignment::

    <name> = <callable>("<name>", <tuple>, <namespace>)

where ``<namespace>`` is the dict created by executing ``<block>``.
The PEP is based on a suggestion [1]_ from Michele Simionato on the
python-dev list. The ``create`` keyword was suggested by Nick
Coghlan.


Motivation
==========

Class statements provide two nice facilities to Python:

   (1) They are the standard Python means of creating a namespace.
   All statements within a class body are executed, and the resulting
   local name bindings are passed as a dict to the metaclass.

   (2) They encourage DRY (don't repeat yourself) by allowing the
   class being created to know the name it is being assigned.

Thus in a simple class statement like::

      class C(object):
          x = 1
          def foo(self):
              return 'bar'

the metaclass (``type``) gets called something like::

     C = type('C', (object,), {'x':1, 'foo':<function foo at ...>})

The class statement is just syntactic sugar for the above assignment
statement, but clearly a very useful sort of syntactic sugar. It
avoids not only the repetition of ``C``, but also simplifies the
creation of the dict by allowing it to be expressed as a series of
statements.

Historically, type instances (a.k.a. class objects) have been the
only objects blessed with this sort of syntactic support. But other
sorts of objects could benefit from such support. For example,
property objects  take three function arguments, but because the
property type cannot be passed a namespace, these functions, though
relevant only to the property, must be declared before it and then
passed as arguments to the property call, e.g.::

     class C(object):
         ...
         def get_x(self):
             ...
         def set_x(self):
             ...
         x = property(get_x, set_x, ...)

There have been a few recipes [2]_ trying to work around this
behavior, but with the new create statement (and an appropriate
definition of property), the getter and setter functions can be
defined in the property's namespace like::

     class C(object):
         ...
         create property x:
             def get(self):
                 ...
             def set(self):
                 ...

The definition of such a property callable could be as simple as::

     def property(name, args, namespace):
         fget = namespace.get('get')
         fset = namespace.get('set')
         fdel = namespace.get('delete')
         doc = namespace.get('__doc__')
         return __builtin__.property(fget, fset, fdel, doc)

Of course, properties are only one of the many possible uses of the
create statement. The create statement is useful in essentially any
situation where a name is associated with a namespace. So, for
example, namespaces could be created as simply as::

     create namespace ns:
         """This creates a namespace named ns with a badger attribute
         and a spam function"""

         badger = 42

         def spam():
             ...

and named, nested hierarchies like XML documents could be created
like::

     create ETobject html:
         "This statement would generate an ElementTree object"

         create ETobject head:
             "generate the head"
             ...

         create ETobject body:
             "generate the body"
             ...

If Python acquires interfaces, given an appropriately defined
``interface`` callable, the create statement can support interface
creation through the syntax::

     create interface C(...):
         ...

which would mean that interface systems like that of Zope would no
longer have to abuse the class syntax to create proper interface
instances.


Specification
=============

Python will translate a create statement::

     create <callable> <name> <tuple>:
         <block>

into the assignment::

     <name> = <callable>("<name>", <tuple>, <namespace>)

where ``<namespace>`` is the dict created by executing ``<block>``.
The ``<tuple>`` expression is optional; if not present, an empty tuple
will be assumed.

A patch is available implementing these semantics [3]_.

The create statement introduces a new keyword, ``create``. Thus in
Python 2.6, the create statement will have to be enabled with a
``from __future__ import create`` statement.


Open Issues
===========

Does the ``create`` keyword break too much code? An investigation of
the standard library by Michele Simionato [4]_ suggests some minor
breakage -- about eight instances. In particular, imaplib.IMAP4
objects expose a ``create()`` method, which could be problematic. Is
there a better keyword for the statement?

Instead of following the class statement precedent of a name, tuple
and namespace arguments, should the function be passed a name, \*args
and \*\*kwargs arguments? This might make the create statement usable
with more existing callables since (name, \*args, \*\*kwargs) matches
more function signatures than (name, args, kwargs). However, changing
the create-statement translation in this manner would break
compatibility with class statements and metaclass usage.


Optional Extensions
===================

Remove the create keyword
-------------------------

It might be possible to remove the create keyword so that such
statements would begin with the callable being called, e.g.::

     namespace ns:
         badger = 42
         def spam():
             ...

     interface C(...):
         ...

However, this would probably add some complexity in the grammar and
so far I (Steven Bethard) have not been able to implement the feature
without the keyword.


Removing __metaclass__ in Python 3000
-------------------------------------

As a side-effect of its generality, the create statement mostly
eliminates the need for the ``__metaclass__`` attribute in class
objects. Thus in Python 3000, instead of::

    class <name> <bases-tuple>:
        __metaclass__ = <metaclass>
        <block>

metaclasses could be supported by using the metaclass as the callable
in a create statement::

    create <metaclass> <name> <bases-tuple>:
        <block>

Removing the ``__metaclass__`` hook would simplify the BUILD_CLASS
opcode a bit.

Removing class statements in Python 3000
----------------------------------------

In the most extreme application of create statements, the class
statement itself could be deprecated in favor of ``create type``
statements.


References
==========

.. [1] Michele Simionato's original suggestion 
(http://mail.python.org/pipermail/python-dev/2005-October/057435.html)
.. [2] Namespace-based property recipe 
(http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442418)
.. [3] Create Statement patch 
(http://ucsu.colorado.edu/~bethard/py/create_stmt.patch)
.. [4] Instances of create in the stdlib 
(http://mail.python.org/pipermail/python-list/2006-April/335159.html)

Copyright
=========

This document has been placed in the public domain.



..
   Local Variables:
   mode: indented-text
   indent-tabs-mode: nil
   sentence-end-double-space: t
   fill-column: 70
   End:



More information about the Python-list mailing list