2006-04-13 09:36:24 -04:00
|
|
|
|
PEP: 359
|
|
|
|
|
Title: The "make" Statement
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Steven Bethard <steven.bethard@gmail.com>
|
2006-05-07 22:20:01 -04:00
|
|
|
|
Status: Withdrawn
|
2006-04-13 09:36:24 -04:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 05-Apr-2006
|
|
|
|
|
Python-Version: 2.6
|
2006-04-18 19:25:47 -04:00
|
|
|
|
Post-History: 05-Apr-2006, 06-Apr-2006, 13-Apr-2006
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>``.
|
2006-04-18 19:25:47 -04:00
|
|
|
|
This is mostly syntactic sugar for::
|
|
|
|
|
|
|
|
|
|
class <name> <tuple>:
|
|
|
|
|
__metaclass__ = <callable>
|
|
|
|
|
<block>
|
|
|
|
|
|
|
|
|
|
and is intended to help more clearly express the intent of the
|
|
|
|
|
statement when something other than a class is being created. Of
|
|
|
|
|
course, other syntax for such a statement is possible, but it is hoped
|
|
|
|
|
that by keeping a strong parallel to the class statement, an
|
|
|
|
|
understanding of how classes and metaclasses work will translate into
|
|
|
|
|
an understanding of how the make-statement works as well.
|
|
|
|
|
|
2006-04-13 09:36:24 -04:00
|
|
|
|
The PEP is based on a suggestion [1]_ from Michele Simionato on the
|
|
|
|
|
python-dev list.
|
|
|
|
|
|
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
Withdrawal Notice
|
|
|
|
|
=================
|
|
|
|
|
|
|
|
|
|
This PEP was withdrawn at Guido's request [2]_. Guido didn't like it,
|
|
|
|
|
and in particular didn't like how the property use-case puts the
|
|
|
|
|
instance methods of a property at a different level than other
|
|
|
|
|
instance methods and requires fixed names for the property functions.
|
|
|
|
|
|
|
|
|
|
|
2006-04-13 09:36:24 -04:00
|
|
|
|
Motivation
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
Class statements provide two nice facilities to Python:
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
(1) They execute a block of statements and provide the resulting
|
|
|
|
|
bindings as a dict to the metaclass.
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
(2) They encourage DRY (don't repeat yourself) by allowing the class
|
|
|
|
|
being created to know the name it is being assigned.
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
Historically, type instances (a.k.a. class objects) have been the
|
|
|
|
|
only objects blessed with this sort of syntactic support. The make
|
|
|
|
|
statement aims to extend this support to other sorts of objects where
|
|
|
|
|
such syntax would also be useful.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Example: simple namespaces
|
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
|
|
Let's say I have some attributes in a module that I access like::
|
|
|
|
|
|
|
|
|
|
mod.thematic_roletype
|
|
|
|
|
mod.opinion_roletype
|
|
|
|
|
|
|
|
|
|
mod.text_format
|
|
|
|
|
mod.html_format
|
|
|
|
|
|
|
|
|
|
and since "Namespaces are one honking great idea", I'd like to be able
|
|
|
|
|
to access these attributes instead as::
|
|
|
|
|
|
|
|
|
|
mod.roletypes.thematic
|
|
|
|
|
mod.roletypes.opinion
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
mod.format.text
|
|
|
|
|
mod.format.html
|
|
|
|
|
|
|
|
|
|
I currently have two main options:
|
|
|
|
|
|
|
|
|
|
(1) Turn the module into a package, turn ``roletypes`` and ``format``
|
|
|
|
|
into submodules, and move the attributes to the submodules.
|
|
|
|
|
|
|
|
|
|
(2) Create ``roletypes`` and ``format`` classes, and move the
|
|
|
|
|
attributes to the classes.
|
|
|
|
|
|
|
|
|
|
The former is a fair chunk of refactoring work, and produces two tiny
|
|
|
|
|
modules without much content. The latter keeps the attributes local
|
|
|
|
|
to the module, but creates classes when there is no intention of ever
|
|
|
|
|
creating instances of those classes.
|
|
|
|
|
|
|
|
|
|
In situations like this, it would be nice to simply be able to declare
|
|
|
|
|
a "namespace" to hold the few attributes. With the new make
|
|
|
|
|
statement, I could introduce my new namespaces with something like::
|
|
|
|
|
|
|
|
|
|
make namespace roletypes:
|
|
|
|
|
thematic = ...
|
|
|
|
|
opinion = ...
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
make namespace format:
|
|
|
|
|
text = ...
|
|
|
|
|
html = ...
|
|
|
|
|
|
|
|
|
|
and keep my attributes local to the module without making classes that
|
|
|
|
|
are never intended to be instantiated. One definition of namespace
|
|
|
|
|
that would make this work is::
|
|
|
|
|
|
|
|
|
|
class namespace(object):
|
|
|
|
|
def __init__(self, name, args, kwargs):
|
|
|
|
|
self.__dict__.update(kwargs)
|
|
|
|
|
|
|
|
|
|
Given this definition, at the end of the make-statements above,
|
|
|
|
|
``roletypes`` and ``format`` would be namespace instances.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Example: GUI objects
|
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
|
|
In GUI toolkits, objects like frames and panels are often associated
|
|
|
|
|
with attributes and functions. With the make-statement, code that
|
|
|
|
|
looks something like::
|
|
|
|
|
|
|
|
|
|
root = Tkinter.Tk()
|
|
|
|
|
frame = Tkinter.Frame(root)
|
|
|
|
|
frame.pack()
|
|
|
|
|
def say_hi():
|
|
|
|
|
print "hi there, everyone!"
|
|
|
|
|
hi_there = Tkinter.Button(frame, text="Hello", command=say_hi)
|
|
|
|
|
hi_there.pack(side=Tkinter.LEFT)
|
|
|
|
|
root.mainloop()
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2007-04-27 20:36:48 -04:00
|
|
|
|
could be rewritten to group the Button's function with its
|
2006-04-18 19:25:47 -04:00
|
|
|
|
declaration::
|
|
|
|
|
|
|
|
|
|
root = Tkinter.Tk()
|
|
|
|
|
frame = Tkinter.Frame(root)
|
|
|
|
|
frame.pack()
|
|
|
|
|
make Tkinter.Button hi_there(frame):
|
|
|
|
|
text = "Hello"
|
|
|
|
|
def command():
|
|
|
|
|
print "hi there, everyone!"
|
|
|
|
|
hi_there.pack(side=Tkinter.LEFT)
|
|
|
|
|
root.mainloop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Example: custom descriptors
|
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
|
|
Since descriptors are used to customize access to an attribute, it's
|
|
|
|
|
often useful to know the name of that attribute. Current Python
|
|
|
|
|
doesn't give an easy way to find this name and so a lot of custom
|
2006-05-07 22:20:01 -04:00
|
|
|
|
descriptors, like Ian Bicking's setonce descriptor [3]_, have to hack
|
2006-04-18 19:25:47 -04:00
|
|
|
|
around this somehow. With the make-statement, you could create a
|
|
|
|
|
``setonce`` attribute like::
|
|
|
|
|
|
|
|
|
|
class A(object):
|
|
|
|
|
...
|
|
|
|
|
make setonce x:
|
|
|
|
|
"A's x attribute"
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
where the ``setonce`` descriptor would be defined like::
|
|
|
|
|
|
|
|
|
|
class setonce(object):
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __init__(self, name, args, kwargs):
|
|
|
|
|
self._name = '_setonce_attr_%s' % name
|
|
|
|
|
self.__doc__ = kwargs.pop('__doc__', None)
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __get__(self, obj, type=None):
|
|
|
|
|
if obj is None:
|
|
|
|
|
return self
|
|
|
|
|
return getattr(obj, self._name)
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __set__(self, obj, value):
|
|
|
|
|
try:
|
|
|
|
|
getattr(obj, self._name)
|
|
|
|
|
except AttributeError:
|
|
|
|
|
setattr(obj, self._name, value)
|
|
|
|
|
else:
|
|
|
|
|
raise AttributeError("Attribute already set")
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def set(self, obj, value):
|
|
|
|
|
setattr(obj, self._name, value)
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __delete__(self, obj):
|
|
|
|
|
delattr(obj, self._name)
|
|
|
|
|
|
|
|
|
|
Note that unlike the original implementation, the private attribute
|
|
|
|
|
name is stable since it uses the name of the descriptor, and therefore
|
|
|
|
|
instances of class A are pickleable.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Example: property namespaces
|
|
|
|
|
----------------------------
|
|
|
|
|
|
|
|
|
|
Python's property type takes three function arguments and a docstring
|
|
|
|
|
argument which, though relevant only to the property, must be declared
|
|
|
|
|
before it and then passed as arguments to the property call, e.g.::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
class C(object):
|
|
|
|
|
...
|
|
|
|
|
def get_x(self):
|
|
|
|
|
...
|
|
|
|
|
def set_x(self):
|
|
|
|
|
...
|
2006-04-18 19:25:47 -04:00
|
|
|
|
x = property(get_x, set_x, "the x of the frobulation")
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
This issue has been brought up before, and Guido [4]_ and others [5]_
|
2006-04-18 19:25:47 -04:00
|
|
|
|
have briefly mused over alternate property syntaxes to make declaring
|
|
|
|
|
properties easier. With the make-statement, the following syntax
|
|
|
|
|
could be supported::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
class C(object):
|
|
|
|
|
...
|
2006-04-18 19:25:47 -04:00
|
|
|
|
make block_property x:
|
|
|
|
|
'''The x of the frobulation'''
|
|
|
|
|
def fget(self):
|
2006-04-13 09:36:24 -04:00
|
|
|
|
...
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def fset(self):
|
2006-04-13 09:36:24 -04:00
|
|
|
|
...
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
with the following definition of ``block_property``::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def block_property(name, args, block_dict):
|
|
|
|
|
fget = block_dict.pop('fget', None)
|
|
|
|
|
fset = block_dict.pop('fset', None)
|
|
|
|
|
fdel = block_dict.pop('fdel', None)
|
|
|
|
|
doc = block_dict.pop('__doc__', None)
|
|
|
|
|
assert not block_dict
|
|
|
|
|
return property(fget, fset, fdel, doc)
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
Example: interfaces
|
|
|
|
|
-------------------
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
Guido [6]_ and others have occasionally suggested introducing
|
2006-04-18 19:25:47 -04:00
|
|
|
|
interfaces into python. Most suggestions have offered syntax along
|
|
|
|
|
the lines of::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
interface IFoo:
|
|
|
|
|
"""Foo blah blah"""
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def fumble(name, count):
|
|
|
|
|
"""docstring"""
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
but since there is currently no way in Python to declare an interface
|
|
|
|
|
in this manner, most implementations of Python interfaces use class
|
|
|
|
|
objects instead, e.g. Zope's::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
class IFoo(Interface):
|
|
|
|
|
"""Foo blah blah"""
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def fumble(name, count):
|
|
|
|
|
"""docstring"""
|
|
|
|
|
|
|
|
|
|
With the new make-statement, these interfaces could instead be
|
|
|
|
|
declared as::
|
|
|
|
|
|
|
|
|
|
make Interface IFoo:
|
|
|
|
|
"""Foo blah blah"""
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def fumble(name, count):
|
|
|
|
|
"""docstring"""
|
|
|
|
|
|
|
|
|
|
which makes the intent (that this is an interface, not a class) much
|
|
|
|
|
clearer.
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
Python will translate a make-statement::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
A patch is available implementing these semantics [7]_.
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
The make-statement introduces a new keyword, ``make``. Thus in Python
|
|
|
|
|
2.6, the make-statement will have to be enabled using ``from
|
2006-04-13 09:36:24 -04:00
|
|
|
|
__future__ import make_statement``.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Open Issues
|
|
|
|
|
===========
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
Keyword
|
|
|
|
|
-------
|
|
|
|
|
|
2006-04-13 09:36:24 -04:00
|
|
|
|
Does the ``make`` keyword break too much code? Originally, the make
|
2023-10-11 08:05:51 -04:00
|
|
|
|
statement used the keyword ``create`` (a suggestion due to Alyssa
|
2006-05-07 22:20:01 -04:00
|
|
|
|
Coghlan). However, investigations into the standard library [8]_ and
|
|
|
|
|
Zope+Plone code [9]_ revealed that ``create`` would break a lot more
|
2006-04-13 09:36:24 -04:00
|
|
|
|
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?
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
Some possible keywords and their counts in the standard library (plus
|
|
|
|
|
some installed packages):
|
|
|
|
|
|
|
|
|
|
* make - 2 (both in tests)
|
|
|
|
|
* create - 19 (including existing function in imaplib)
|
|
|
|
|
* build - 83 (including existing class in distutils.command.build)
|
|
|
|
|
* construct - 0
|
|
|
|
|
* produce - 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The make-statement as an alternate constructor
|
|
|
|
|
----------------------------------------------
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
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
|
2006-04-18 19:25:47 -04:00
|
|
|
|
that if found would be called instead of ``__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::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
So the question is, will many types want to use the make-statement as
|
|
|
|
|
an alternate constructor? And if so, does that alternate constructor
|
|
|
|
|
need to have the same name as the original constructor?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Customizing the dict in which the block is executed
|
|
|
|
|
---------------------------------------------------
|
|
|
|
|
|
|
|
|
|
Should users of the make-statement be able to determine in which dict
|
|
|
|
|
object the code is executed? This would allow the make-statement to
|
|
|
|
|
be used in situations where a normal dict object would not suffice,
|
|
|
|
|
e.g. if order and repeated names must be allowed. Allowing this sort
|
|
|
|
|
of customization could allow XML to be written without repeating
|
|
|
|
|
element names, and with nesting of make-statements corresponding to
|
|
|
|
|
nesting of XML elements::
|
|
|
|
|
|
|
|
|
|
make Element html:
|
|
|
|
|
make Element body:
|
|
|
|
|
text('before first h1')
|
|
|
|
|
make Element h1:
|
|
|
|
|
attrib(style='first')
|
|
|
|
|
text('first h1')
|
|
|
|
|
tail('after first h1')
|
|
|
|
|
make Element h1:
|
|
|
|
|
attrib(style='second')
|
|
|
|
|
text('second h1')
|
|
|
|
|
tail('after second h1')
|
|
|
|
|
|
|
|
|
|
If the make-statement tried to get the dict in which to execute its
|
|
|
|
|
block by calling the callable's ``__make_dict__`` method, the
|
|
|
|
|
following code would allow the make-statement to be used as above::
|
|
|
|
|
|
|
|
|
|
class Element(object):
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
class __make_dict__(dict):
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
self._super = super(Element.__make_dict__, self)
|
|
|
|
|
self._super.__init__(*args, **kwargs)
|
|
|
|
|
self.elements = []
|
|
|
|
|
self.text = None
|
|
|
|
|
self.tail = None
|
|
|
|
|
self.attrib = {}
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __getitem__(self, name):
|
|
|
|
|
try:
|
|
|
|
|
return self._super.__getitem__(name)
|
|
|
|
|
except KeyError:
|
|
|
|
|
if name in ['attrib', 'text', 'tail']:
|
|
|
|
|
return getattr(self, 'set_%s' % name)
|
|
|
|
|
else:
|
|
|
|
|
return globals()[name]
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __setitem__(self, name, value):
|
|
|
|
|
self._super.__setitem__(name, value)
|
|
|
|
|
self.elements.append(value)
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def set_attrib(self, **kwargs):
|
|
|
|
|
self.attrib = kwargs
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def set_text(self, text):
|
|
|
|
|
self.text = text
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def set_tail(self, text):
|
|
|
|
|
self.tail = text
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
def __new__(cls, name, args, edict):
|
|
|
|
|
get_element = etree.ElementTree.Element
|
|
|
|
|
result = get_element(name, attrib=edict.attrib)
|
|
|
|
|
result.text = edict.text
|
|
|
|
|
result.tail = edict.tail
|
|
|
|
|
for element in edict.elements:
|
|
|
|
|
result.append(element)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
Note, however, that the code to support this is somewhat fragile --
|
|
|
|
|
it has to magically populate the namespace with ``attrib``, ``text``
|
|
|
|
|
and ``tail``, and it assumes that every name binding inside the make
|
|
|
|
|
statement body is creating an Element. As it stands, this code would
|
|
|
|
|
break with the introduction of a simple for-loop to any one of the
|
|
|
|
|
make-statement bodies, because the for-loop would bind a name to a
|
|
|
|
|
non-Element object. This could be worked around by adding some sort
|
|
|
|
|
of isinstance check or attribute examination, but this still results
|
|
|
|
|
in a somewhat fragile solution.
|
|
|
|
|
|
|
|
|
|
It has also been pointed out that the with-statement can provide
|
|
|
|
|
equivalent nesting with a much more explicit syntax::
|
|
|
|
|
|
|
|
|
|
with Element('html') as html:
|
|
|
|
|
with Element('body') as body:
|
|
|
|
|
body.text = 'before first h1'
|
|
|
|
|
with Element('h1', style='first') as h1:
|
|
|
|
|
h1.text = 'first h1'
|
|
|
|
|
h1.tail = 'after first h1'
|
|
|
|
|
with Element('h1', style='second') as h1:
|
|
|
|
|
h1.text = 'second h1'
|
|
|
|
|
h1.tail = 'after second h1'
|
2017-03-24 17:11:33 -04:00
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
And if the repetition of the element names here is too much of a DRY
|
2019-07-03 14:20:45 -04:00
|
|
|
|
violation, it is also possible to eliminate all as-clauses except for
|
2006-05-07 22:20:01 -04:00
|
|
|
|
the first by adding a few methods to Element. [10]_
|
2006-04-18 19:25:47 -04:00
|
|
|
|
|
|
|
|
|
So are there real use-cases for executing the block in a dict of a
|
|
|
|
|
different type? And if so, should the make-statement be extended to
|
|
|
|
|
support them?
|
|
|
|
|
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
-------------------------------------
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
As a side-effect of its generality, the make-statement mostly
|
2006-04-13 09:36:24 -04:00
|
|
|
|
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
|
2006-04-18 19:25:47 -04:00
|
|
|
|
in a make-statement::
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
make <metaclass> <name> <bases-tuple>:
|
|
|
|
|
<block>
|
|
|
|
|
|
|
|
|
|
Removing the ``__metaclass__`` hook would simplify the BUILD_CLASS
|
|
|
|
|
opcode a bit.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Removing class statements in Python 3000
|
|
|
|
|
----------------------------------------
|
|
|
|
|
|
2006-04-18 19:25:47 -04:00
|
|
|
|
In the most extreme application of make-statements, the class
|
2006-04-13 09:36:24 -04:00
|
|
|
|
statement itself could be deprecated in favor of ``make type``
|
|
|
|
|
statements.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
.. [1] Michele Simionato's original suggestion
|
2017-06-11 15:02:39 -04:00
|
|
|
|
(https://mail.python.org/pipermail/python-dev/2005-October/057435.html)
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [2] Guido requests withdrawal
|
2017-06-11 15:02:39 -04:00
|
|
|
|
(https://mail.python.org/pipermail/python-3000/2006-April/000936.html)
|
2006-05-07 22:20:01 -04:00
|
|
|
|
|
|
|
|
|
.. [3] Ian Bicking's setonce descriptor
|
2006-04-18 19:25:47 -04:00
|
|
|
|
(http://blog.ianbicking.org/easy-readonly-attributes.html)
|
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [4] Guido ponders property syntax
|
2017-06-11 15:02:39 -04:00
|
|
|
|
(https://mail.python.org/pipermail/python-dev/2005-October/057404.html)
|
2006-04-18 19:25:47 -04:00
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [5] Namespace-based property recipe
|
2006-04-13 09:36:24 -04:00
|
|
|
|
(http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442418)
|
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [6] Python interfaces
|
2006-04-18 19:25:47 -04:00
|
|
|
|
(http://www.artima.com/weblogs/viewpost.jsp?thread=86641)
|
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [7] Make Statement patch
|
2006-04-13 09:36:24 -04:00
|
|
|
|
(http://ucsu.colorado.edu/~bethard/py/make_statement.patch)
|
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [8] Instances of create in the stdlib
|
2017-06-11 15:02:39 -04:00
|
|
|
|
(https://mail.python.org/pipermail/python-list/2006-April/335159.html)
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [9] Instances of create in Zope+Plone
|
2017-06-11 15:02:39 -04:00
|
|
|
|
(https://mail.python.org/pipermail/python-list/2006-April/335284.html)
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
2006-05-07 22:20:01 -04:00
|
|
|
|
.. [10] Eliminate as-clauses in with-statement XML
|
2017-06-11 15:02:39 -04:00
|
|
|
|
(https://mail.python.org/pipermail/python-list/2006-April/336774.html)
|
2006-04-18 19:25:47 -04:00
|
|
|
|
|
2006-04-13 09:36:24 -04:00
|
|
|
|
|
|
|
|
|
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:
|