275 lines
7.9 KiB
Plaintext
275 lines
7.9 KiB
Plaintext
|
PEP: 359
|
|||
|
Title: The "make" Statement
|
|||
|
Version: $Revision$
|
|||
|
Last-Modified: $Date$
|
|||
|
Author: Steven Bethard <steven.bethard@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 ``make`` statement. The proposed syntax and semantics parallel
|
|||
|
the syntax for class definition, and so::
|
|||
|
|
|||
|
make <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.
|
|||
|
|
|||
|
|
|||
|
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 with 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 make statement (and an appropriate
|
|||
|
definition of property), the getter and setter functions can be
|
|||
|
defined in the property's namespace like::
|
|||
|
|
|||
|
class C(object):
|
|||
|
...
|
|||
|
make 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
|
|||
|
make statement. The make 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::
|
|||
|
|
|||
|
make namespace ns:
|
|||
|
"""This creates a namespace named ns with a badger attribute
|
|||
|
and a spam function"""
|
|||
|
|
|||
|
badger = 42
|
|||
|
|
|||
|
def spam():
|
|||
|
...
|
|||
|
|
|||
|
And if Python acquires interfaces, given an appropriately defined
|
|||
|
``interface`` callable, the make statement can support interface
|
|||
|
creation through the syntax::
|
|||
|
|
|||
|
make interface C(...):
|
|||
|
...
|
|||
|
|
|||
|
This 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 make statement::
|
|||
|
|
|||
|
make <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 make statement introduces a new keyword, ``make``. Thus in Python
|
|||
|
2.6, the make statement will have to be enabled using ``from
|
|||
|
__future__ import make_statement``.
|
|||
|
|
|||
|
|
|||
|
Open Issues
|
|||
|
===========
|
|||
|
|
|||
|
Does the ``make`` keyword break too much code? Originally, the make
|
|||
|
statement used the keyword ``create`` (a suggestion due to Nick
|
|||
|
Coghlan). However, investigations into the standard library [4]_ and
|
|||
|
Zope+Plone code [5]_ revealed that ``create`` would break a lot more
|
|||
|
code, so ``make`` was adopted as the keyword instead. However, there
|
|||
|
are still a few instances where ``make`` would break code. Is there a
|
|||
|
better keyword for the statement?
|
|||
|
|
|||
|
**********
|
|||
|
|
|||
|
Currently, there are not many functions which have the signature
|
|||
|
``(name, args, kwargs)``. That means that something like::
|
|||
|
|
|||
|
make dict params:
|
|||
|
x = 1
|
|||
|
y = 2
|
|||
|
|
|||
|
is currently impossible because the dict constructor has a different
|
|||
|
signature. Does this sort of thing need to be supported? One
|
|||
|
suggestion, by Carl Banks, would be to add a ``__make__`` magic method
|
|||
|
that would be called before ``__call__``. For types, the ``__make__``
|
|||
|
method would be identical to ``__call__`` (and thus unnecessary), but
|
|||
|
dicts could support the make statement by defining a ``__make__``
|
|||
|
method on the dict type that looks something like::
|
|||
|
|
|||
|
def __make__(cls, name, args, kwargs):
|
|||
|
return cls(**kwargs)
|
|||
|
|
|||
|
Of course, rather than adding another magic method, the dict type
|
|||
|
could just grow a classmethod something like ``dict.fromblock`` that
|
|||
|
could be used like::
|
|||
|
|
|||
|
make dict.fromblock params:
|
|||
|
x = 1
|
|||
|
y = 2
|
|||
|
|
|||
|
|
|||
|
Optional Extensions
|
|||
|
===================
|
|||
|
|
|||
|
Remove the make keyword
|
|||
|
-------------------------
|
|||
|
|
|||
|
It might be possible to remove the make keyword so that such
|
|||
|
statements would begin with the callable being called, e.g.::
|
|||
|
|
|||
|
namespace ns:
|
|||
|
badger = 42
|
|||
|
def spam():
|
|||
|
...
|
|||
|
|
|||
|
interface C(...):
|
|||
|
...
|
|||
|
|
|||
|
However, almost all other Python statements begin with a keyword, and
|
|||
|
removing the keyword would make it harder to look up this construct in
|
|||
|
the documentation. Additionally, this would 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 make 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 make statement::
|
|||
|
|
|||
|
make <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 make statements, the class
|
|||
|
statement itself could be deprecated in favor of ``make 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] Make Statement patch
|
|||
|
(http://ucsu.colorado.edu/~bethard/py/make_statement.patch)
|
|||
|
|
|||
|
.. [4] Instances of create in the stdlib
|
|||
|
(http://mail.python.org/pipermail/python-list/2006-April/335159.html)
|
|||
|
|
|||
|
.. [5] Instances of create in Zope+Plone
|
|||
|
(http://mail.python.org/pipermail/python-list/2006-April/335284.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
|
|||
|
coding: utf-8
|
|||
|
End:
|