By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,855 Members | 1,970 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,855 IT Pros & Developers. It's quick & easy.

PEP 359: The "make" Statement

P: n/a
Ok, I finally have a PEP number. Here's the most updated version of the
"make" statement PEP. I'll be posting it shortly to python-dev.

Thanks again for the previous discussion and suggestions!
PEP: 359
Title: The "make" Statement
Version: $Revision: 45366 $
Last-Modified: $Date: 2006-04-13 07:36:24 -0600 (Thu, 13 Apr 2006) $
Author: Steven Bethard <st************@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/pyt...er/057435.html)

... [2] Namespace-based property recipe
(http://aspn.activestate.com/ASPN/Coo.../Recipe/442418)

... [3] Make Statement patch
(http://ucsu.colorado.edu/~bethard/py...tatement.patch)

... [4] Instances of create in the stdlib
(http://mail.python.org/pipermail/pyt...il/335159.html)

... [5] Instances of create in Zope+Plone
(http://mail.python.org/pipermail/pyt...il/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:
Apr 13 '06 #1
Share this Question
Share on Google+
28 Replies


P: n/a
"make type" is uber leet

Apr 13 '06 #2

P: n/a
On Thu, 13 Apr 2006 13:39:14 -0700, gangesmaster wrote:
"make type" is uber leet


So you're against it then?
--
Steven.

Apr 14 '06 #3

P: n/a
Steven Bethard wrote:
Ok, I finally have a PEP number. Here's the most updated version of the
"make" statement PEP. I'll be posting it shortly to python-dev.

Thanks again for the previous discussion and suggestions!


I find it very interesting.

My only complaint is that it is limited to things that can be described
as a namespace, where the order of declaration is lost. This problem is
also true with metaclasses, but it is more acceptable since they are for
classes.

For example, it would be nice to use such a feature to define C
structures that are to be exported in a binary format without having to
use a hidden counter or other hacks. I have no idea of the
implementation implications, but it would be nice to have the capability
to override the namespace type to use something else than dict, so that
it can be filled with symbols one statement at a time.

The callable could have something like a __namespacetype__ that could be
use instead of dict. That type would have to implement __setitem__.

Regards,
Nicolas
Apr 14 '06 #4

P: n/a
Em Qui, 2006-04-13 *s 23:17 -0400, Nicolas Fleury escreveu:
The callable could have something like a __namespacetype__ that could be
use instead of dict. That type would have to implement __setitem__.


Or the namespace variable could be a list of tuples.

--
Felipe.

Apr 14 '06 #5

P: n/a
Nicolas Fleury wrote:
I have no idea of the
implementation implications, but it would be nice to have the
capability to override the namespace type to use something else
than dict, so that it can be filled with symbols one statement at a
time.


I agree. I have sometimes wanted this ability for classes, so that
class definitions could map assignments onto class attributes in some
way besides blindly stuffing into a dict.

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
Apr 14 '06 #6

P: n/a
Nicolas Fleury wrote:
Steven Bethard wrote:
Ok, I finally have a PEP number. Here's the most updated version of
the "make" statement PEP. I'll be posting it shortly to python-dev.

Thanks again for the previous discussion and suggestions!


I find it very interesting.

My only complaint is that it is limited to things that can be described
as a namespace, where the order of declaration is lost. This problem is
also true with metaclasses, but it is more acceptable since they are for
classes.


Yep, this seems to be the biggest complaint. I'm waiting for write
access to the repository, but here's a clip from the upcoming update:

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

....

Should users of the make statement be able to determine in which dict
object the code is executed? The make statement could look for a
``__make_dict__`` attribute and call it to allow things like::

make Element html:
make Element body:
make Element h1:
'''First heading text'''
make Element h1:
'''Second heading text'''

where a normal dict object would not suffice since order and repeated
names must be allowed. Assuming that the ``__make_dict__`` attribute
was called to get the dict in which the block should be executed, the
following code should make the above make statements work::

class Element(object):

class __make_dict__(dict):
def __init__(self, *args, **kwargs):
self._super = super(Element.__make_dict__, self)
self._super.__init__(*args, **kwargs)
self.values = []
def __getitem__(self, name):
try:
return self._super.__getitem__(name)
except KeyError:
return globals()[name]
def __setitem__(self, name, value):
self._super.__setitem__(name, value)
if not name.startswith('__'):
self.values.append(value)

def __new__(cls, name, args, edict):
result = etree.ElementTree.Element(name)
result.text = edict.pop('__doc__', None)
print edict.values
for element in edict.values:
result.append(element)
return result
STeVe
Apr 14 '06 #7

P: n/a
Steven Bethard wrote:
Should users of the make statement be able to determine in which dict
object the code is executed? The make statement could look for a
``__make_dict__`` attribute and call it to allow things like::

make Element html:
make Element body:
make Element h1:
'''First heading text'''
make Element h1:
'''Second heading text'''


I'm concerned about the magic implied here for __doc__:

make Element p:
'''This is '''
make Element strong:
'''not'''
'''going to work'''
There is another effect which should be considered here. If you allow
Element to create an object to be used as the namespace, then as well as
doing special tracking when values are set in the namespace it can also
pre-seed it with names which magically appear in scope within the make.

e.g.

make Element html:
make Element body:
make Element p:
text('But this ')
make Element strong:
text('could')
text(' be made to work')

or even:

make Element p:
text('This would ')
strong('also')
text(' work')

where text and strong are readable in the Element namespace (there doesn't
actually have to be any relationship between the names you can access and
the names you set).
Apr 14 '06 #8

P: n/a
Duncan Booth wrote:
Steven Bethard wrote:
Should users of the make statement be able to determine in which dict
object the code is executed? The make statement could look for a
``__make_dict__`` attribute and call it to allow things like::

make Element html:
make Element body:
make Element h1:
'''First heading text'''
make Element h1:
'''Second heading text'''

[snip] There is another effect which should be considered here. If you allow
Element to create an object to be used as the namespace, then as well as
doing special tracking when values are set in the namespace it can also
pre-seed it with names which magically appear in scope within the make.

e.g.

make Element html:
make Element body:
make Element p:
text('But this ')
make Element strong:
text('could')
text(' be made to work')


This is nice. I'll have to play around with it a bit to see how hard it
would be to make it work.

STeVe
Apr 14 '06 #9

P: n/a
Steven Bethard wrote:
Duncan Booth wrote:
Steven Bethard wrote:
Should users of the make statement be able to determine in which dict
object the code is executed? The make statement could look for a
``__make_dict__`` attribute and call it to allow things like::

make Element html:
make Element body:
make Element h1:
'''First heading text'''
make Element h1:
'''Second heading text'''

[snip]
There is another effect which should be considered here. If you allow
Element to create an object to be used as the namespace, then as well
as doing special tracking when values are set in the namespace it can
also pre-seed it with names which magically appear in scope within the
make.

e.g.

make Element html:
make Element body:
make Element p:
text('But this ')
make Element strong:
text('could')
text(' be made to work')


This is nice. I'll have to play around with it a bit to see how hard it
would be to make it work.


Okay, I think it'll work[1]. I'm going to update this section to
something more like:
Open Issues
===========

....

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 like::

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')

assert etree.ElementTree.tostring(body) == '''\
<html>\
<body>\
before first h1\
<h1 style="first">first h1</h1>\
after first h1\
<h1 style="second">second h1</h1>\
after second h1\
</body>\
</html>\
'''

Assuming that the make statement calls the callable's
``__make_dict__`` to get the dict in which to execute the code, the
following should make the above make statements work::

class Element(object):

class __make_dict__(dict):

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 = {}

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]

def __setitem__(self, name, value):
self._super.__setitem__(name, value)
self.elements.append(value)

def set_attrib(self, **kwargs):
self.attrib = kwargs

def set_text(self, text):
self.text = text

def set_tail(self, text):
self.tail = text

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

[1] Here's the code I used to test it.
def make(callable, name, args, block_string): .... try:
.... make_dict = callable.__make_dict__
.... except AttributeError:
.... make_dict = dict
.... block_dict = make_dict()
.... exec block_string in block_dict
.... return callable(name, args, block_dict)
.... class Element(object): .... class __make_dict__(dict):
.... 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 = {}
.... 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]
.... def __setitem__(self, name, value):
.... self._super.__setitem__(name, value)
.... self.elements.append(value)
.... def set_attrib(self, **kwargs):
.... self.attrib = kwargs
.... def set_text(self, text):
.... self.text = text
.... def set_tail(self, text):
.... self.tail = text
.... 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
.... body = make(Element, 'body', (), textwrap.dedent("""\ .... text('before first h1')
.... h1 = make(Element, 'h1', (), textwrap.dedent('''
.... attrib(style='first')
.... text('first h1')
.... tail('after first h1')
.... '''))
.... h1 = make(Element, 'h1', (), textwrap.dedent('''
.... attrib(style='second')
.... text('second h1')
.... tail('after second h1')
.... '''))
.... """)) assert etree.ElementTree.tostring(body) == '''\

.... <body>\
.... before first h1\
.... <h1 style="first">first h1</h1>\
.... after first h1\
.... <h1 style="second">second h1</h1>\
.... after second h1\
.... </body>\
.... '''
STeVe
Apr 14 '06 #10

P: n/a
Em Sex, 2006-04-14 *s 09:31 -0600, Steven Bethard escreveu:
[1] Here's the code I used to test it.
>>> def make(callable, name, args, block_string): ... try:
... make_dict = callable.__make_dict__
... except AttributeError:
... make_dict = dict
... block_dict = make_dict()
... exec block_string in block_dict
... return callable(name, args, block_dict)
... >>> (snip)


I think it would be nice not to put those ">>>" and "..." to make copy
and paste easier. Okay, I know we can do "".join(line[4:] for line in
text), but that's just my humble opinion.

--
Felipe.

Apr 14 '06 #11

P: n/a
Steven Bethard wrote in news:Pf******************************@comcast.com
in comp.lang.python:
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?


I don't know wether this has been suggested or not, but
what about def:

def namespace ns:
x = 1

def type blah(object):
pass

def property x:
def get():
return ns.x
Rob.
--
http://www.victim-prime.dsl.pipex.com/
Apr 14 '06 #12

P: n/a
Felipe Almeida Lessa wrote:
Em Sex, 2006-04-14 *s 09:31 -0600, Steven Bethard escreveu:
[1] Here's the code I used to test it.
>>> def make(callable, name, args, block_string):

... try:
... make_dict = callable.__make_dict__
... except AttributeError:
... make_dict = dict
... block_dict = make_dict()
... exec block_string in block_dict
... return callable(name, args, block_dict)
...
>>> (snip)


I think it would be nice not to put those ">>>" and "..." to make copy
and paste easier. Okay, I know we can do "".join(line[4:] for line in
text), but that's just my humble opinion.


Note that there's a "special paste" in wxPython PyShell, with which you
can copy/paste these lines.

Nicolas
Apr 14 '06 #13

P: n/a
Rob Williscroft wrote:
Steven Bethard wrote in news:Pf******************************@comcast.com
in comp.lang.python:
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?


I don't know wether this has been suggested or not, but
what about def:

def namespace ns:
x = 1

def type blah(object):
pass

def property x:
def get():
return ns.x


I think that's probably a bad idea because it would make people think
that the statement acts like a function definition, when it actually
acts like a class definition.

STeVe
Apr 14 '06 #14

P: n/a
Steven Bethard wrote:
Steven Bethard wrote:
Duncan Booth wrote:
Steven Bethard wrote:
Should users of the make statement be able to determine in which dict
object the code is executed? The make statement could look for a
``__make_dict__`` attribute and call it to allow things like::

make Element html:
make Element body:
make Element h1:
'''First heading text'''
make Element h1:
'''Second heading text'''
[snip]
There is another effect which should be considered here. If you allow
Element to create an object to be used as the namespace, then as well
as doing special tracking when values are set in the namespace it can
also pre-seed it with names which magically appear in scope within the
make.

e.g.

make Element html:
make Element body:
make Element p:
text('But this ')
make Element strong:
text('could')
text(' be made to work')


This is nice. I'll have to play around with it a bit to see how hard it
would be to make it work.

Okay, I think it'll work[1]. I'm going to update this section to
something more like:
Open Issues
===========

...

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 like::


I think this PEP is going off the rails. It's primary virtue was that it
was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

Once it starts calling secret magic methods behind the scenes it's
losing that virture. And for what? Supporting some use cases that have
reasonable solutions already?

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')

What's the virtue of this form? Is it the indentation? If so, I suspect
some relatively pretty solution could be manufactured using the 'with'
syntax. Does anyone really write html 'by hand' in this manner anyway? I
think this approach may start looking a lot less appealing when you are
generating the HTML from some other data. Then you have loops inside the
body. Somehow you have to clean up all the leftover loop variables so
they don't end up in your document. However, that would require some
surgery and increased complexity in Element. It all looks like it would
be messy and perhaps useless in real life.

Regards,

-tim

assert etree.ElementTree.tostring(body) == '''\
<html>\
<body>\
before first h1\
<h1 style="first">first h1</h1>\
after first h1\
<h1 style="second">second h1</h1>\
after second h1\
</body>\
</html>\
'''

Assuming that the make statement calls the callable's
``__make_dict__`` to get the dict in which to execute the code, the
following should make the above make statements work::

class Element(object):

class __make_dict__(dict):

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 = {}

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]

def __setitem__(self, name, value):
self._super.__setitem__(name, value)
self.elements.append(value)

def set_attrib(self, **kwargs):
self.attrib = kwargs

def set_text(self, text):
self.text = text

def set_tail(self, text):
self.tail = text

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

[1] Here's the code I used to test it.
>>> def make(callable, name, args, block_string): ... try:
... make_dict = callable.__make_dict__
... except AttributeError:
... make_dict = dict
... block_dict = make_dict()
... exec block_string in block_dict
... return callable(name, args, block_dict)
... >>> class Element(object): ... class __make_dict__(dict):
... 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 = {}
... 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]
... def __setitem__(self, name, value):
... self._super.__setitem__(name, value)
... self.elements.append(value)
... def set_attrib(self, **kwargs):
... self.attrib = kwargs
... def set_text(self, text):
... self.text = text
... def set_tail(self, text):
... self.tail = text
... 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
... >>> body = make(Element, 'body', (), textwrap.dedent("""\ ... text('before first h1')
... h1 = make(Element, 'h1', (), textwrap.dedent('''
... attrib(style='first')
... text('first h1')
... tail('after first h1')
... '''))
... h1 = make(Element, 'h1', (), textwrap.dedent('''
... attrib(style='second')
... text('second h1')
... tail('after second h1')
... '''))
... """)) >>> assert etree.ElementTree.tostring(body) == '''\

... <body>\
... before first h1\
... <h1 style="first">first h1</h1>\
... after first h1\
... <h1 style="second">second h1</h1>\
... after second h1\
... </body>\
... '''
STeVe


Apr 14 '06 #15

P: n/a
Tim Hochberg wrote:
Steven Bethard wrote:
Steven Bethard wrote:
Duncan Booth wrote:
make Element html:
make Element body:
make Element p:
text('But this ')
make Element strong:
text('could')
text(' be made to work')

This is nice. I'll have to play around with it a bit to see how hard
it would be to make it work.


Okay, I think it'll work[1]. I'm going to update this section to
something more like:
Open Issues
===========

...

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 like::


I think this PEP is going off the rails. It's primary virtue was that it
was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

Once it starts calling secret magic methods behind the scenes it's
losing that virture. And for what? Supporting some use cases that have
reasonable solutions already?


That's why it's in the Open Issues section. I expect most of these open
issues to be resolved by rejection. (At least, that's my preferred
resolution.) But since they people have brought them up, I think they
need to be addressed as completely as possible.

But I think you make a good point that this particular case can be just
as easily done using a with-statement (I think). I'll add that to this
part of the PEP (once I'm sure it works).

STeVe
Apr 14 '06 #16

P: n/a
Steven Bethard wrote:
Tim Hochberg wrote:
Steven Bethard wrote:
Steven Bethard wrote:
Duncan Booth wrote:
> make Element html:
> make Element body:
> make Element p:
> text('But this ')
> make Element strong:
> text('could')
> text(' be made to work')

This is nice. I'll have to play around with it a bit to see how
hard it would be to make it work.

Okay, I think it'll work[1]. I'm going to update this section to
something more like:
Open Issues
===========

...

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 like::


I think this PEP is going off the rails. It's primary virtue was that
it was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

Once it starts calling secret magic methods behind the scenes it's
losing that virture. And for what? Supporting some use cases that have
reasonable solutions already?


That's why it's in the Open Issues section. I expect most of these open
issues to be resolved by rejection. (At least, that's my preferred
resolution.) But since they people have brought them up, I think they
need to be addressed as completely as possible.

But I think you make a good point that this particular case can be just
as easily done using a with-statement (I think). I'll add that to this
part of the PEP (once I'm sure it works).


Hmm... Actually, while the with-statement can probably help out with
the nesting, it doesn't help out with the DRY; you still have to repeat
the element name (once for the call to Element, and once as the name
that Element object is bound to).

STeVe
Apr 14 '06 #17

P: n/a
Steven Bethard wrote:
Steven Bethard wrote:
Tim Hochberg wrote:
Steven Bethard wrote:

Steven Bethard wrote:

>Duncan Booth wrote:
>
>>make Element html:
>> make Element body:
>> make Element p:
>> text('But this ')
>> make Element strong:
>> text('could')
>> text(' be made to work')
>
>This is nice. I'll have to play around with it a bit to see how
>hard it would be to make it work.

Okay, I think it'll work[1]. I'm going to update this section to
something more like:
Open Issues
===========

...

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 like::

I think this PEP is going off the rails. It's primary virtue was that
it was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

Once it starts calling secret magic methods behind the scenes it's
losing that virture. And for what? Supporting some use cases that have
reasonable solutions already?


That's why it's in the Open Issues section. I expect most of these open
issues to be resolved by rejection. (At least, that's my preferred
resolution.) But since they people have brought them up, I think they
need to be addressed as completely as possible.

But I think you make a good point that this particular case can be just
as easily done using a with-statement (I think). I'll add that to this
part of the PEP (once I'm sure it works).

Hmm... Actually, while the with-statement can probably help out with
the nesting, it doesn't help out with the DRY; you still have to repeat
the element name (once for the call to Element, and once as the name
that Element object is bound to).

I don't think that's correct. I think that with a suitably designed
HtmlDocument object, the following should be possible:

with HtmlDocument("Title") as doc:
with doc.element("body"):
doc.text("before first h1")
with doc.element("h1", style="first"):
doc.text("first h1")
# I don't understand the point of tail, but you could do that too
doc.text("after first h1")
with doc.element("h1", style="second"):
doc.text("second h1")
doc.text("after second h1")

That seems reasonably DRY compliant. Doc would simply stack and unstack
the attributes on the way in and out of the with blocks. This arguably
maps better to the underlying HTML as well.

I'd like to reiterate my point that, as far as I can tell, the make
statement won't actually work for creating HTML in all but the most
trivial of cases. Consider:

with HtmlDocument("Title Here") as doc:
with doc.element("body"):
with doc.element("h1"):
doc.text("An ordered list")
with doc.element("ol"): # Ordered list
for value in some_list:
doc.listitem(value)

If I try to translate this to make syntax, I get into trouble. I end up
with 'value' getting set as an element over and over again. Not at all
what I want! I suppose you could filter your expression so that only
things that subtype some marker class get added, but that's piling
weirdness on top of confusion; and good sign that the whole idea is
better off abandoned.

-tim


Apr 15 '06 #18

P: n/a
Tim Hochberg ha scritto:
I think this PEP is going off the rails. It's primary virtue was that it
was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

Once it starts calling secret magic methods behind the scenes it's
losing that virture. And for what? Supporting some use cases that have
reasonable solutions already?


FWIW, this is my feeling too. Let's keep it simple, please!

Michele Simionato

Apr 15 '06 #19

P: n/a
Tim Hochberg wrote:
Steven Bethard wrote:
Steven Bethard wrote:
Tim Hochberg wrote:

Steven Bethard wrote:

> Steven Bethard wrote:
>
>> Duncan Booth wrote:
>>
>>> make Element html:
>>> make Element body:
>>> make Element p:
>>> text('But this ')
>>> make Element strong:
>>> text('could')
>>> text(' be made to work')
>>
>>
>> This is nice. I'll have to play around with it a bit to see how
>> hard it would be to make it work.
>
>
> Okay, I think it'll work[1]. I'm going to update this section to
> something more like:
>
>
> Open Issues
> ===========
>
> ...
>
> 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 like::
I think this PEP is going off the rails. It's primary virtue was
that it was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

Once it starts calling secret magic methods behind the scenes it's
losing that virture. And for what? Supporting some use cases that
have reasonable solutions already?
That's why it's in the Open Issues section. I expect most of these
open issues to be resolved by rejection. (At least, that's my
preferred resolution.) But since they people have brought them up,
I think they need to be addressed as completely as possible.

But I think you make a good point that this particular case can be
just as easily done using a with-statement (I think). I'll add that
to this part of the PEP (once I'm sure it works).
Hmm... Actually, while the with-statement can probably help out with
the nesting, it doesn't help out with the DRY; you still have to
repeat the element name (once for the call to Element, and once as
the name that Element object is bound to).


I don't think that's correct. I think that with a suitably designed
HtmlDocument object, the following should be possible:

with HtmlDocument("Title") as doc:
with doc.element("body"):
doc.text("before first h1")
with doc.element("h1", style="first"):
doc.text("first h1")
# I don't understand the point of tail, but you could do that too
doc.text("after first h1")
with doc.element("h1", style="second"):
doc.text("second h1")
doc.text("after second h1")

Here's code to do this. It would be probably be better to use elment
tree or some such instead of pushing out the HTML directly, but this
should get the idea across (testing using 2.5a1):

class HtmlTag(object):
def __init__(self, document, type, attribs):
self.document = document
self.type = type
self.attribs = attribs
def __context__(self):
return self
def _format_attribs(self):
if not self.attribs:
return ''
return ' ' + ' '.join('%s="%s"' % (k,v) for
k, v in self.attribs.items())
def __enter__(self):
self.document.entities.append('<%s%s>' % (self.type,
self._format_attribs()))
return self
def __exit__(self, type, value, traceback):
self.document.entities.append('</%s>' % self.type)
def add(self):
self.document.entities.append('<%s%s/>' % (self.type,
self._format_attribs()))

class HtmlDocument(object):
def __init__(self):
self.entities = []
def tag(self, type, **atribs):
return HtmlTag(self, type, atribs)
def text(self, value):
self.entities.append(value)
def tostring(self):
return ''.join(self.entities)
def __context__(self):
return self
def __enter__(self):
self.entities.append('<html>')
return self
def __exit__(self, type, value, traceback):
if not (type is value is traceback is None):
raise type(value)
self.entities.append('</html>')

And here are some simple examples:

with HtmlDocument() as doc:
with doc.tag("body"):
doc.text("before first h1")
with doc.tag("h1", style="first"):
doc.text("first h1")
doc.text("after first h1")
with doc.tag("h1", style="second"):
doc.text("second h1")
doc.text("after second h1")

expected = '''\
<html>\
<body>\
before first h1\
<h1 style="first">first h1</h1>\
after first h1\
<h1 style="second">second h1</h1>\
after second h1\
</body>\
</html>\
'''
print doc.tostring() == expected

some_list = ["foo", "bar", 'bazz', "froodle"]

with HtmlDocument() as doc:
with doc.tag("body"):
with doc.tag("h1"):
doc.text("An ordered list")
with doc.tag("ol"):
for value in some_list:
with doc.tag('li'):
doc.text(value)

print doc.tostring()


Regards,

-tim
That seems reasonably DRY compliant. Doc would simply stack and
unstack the attributes on the way in and out of the with blocks. This
arguably maps better to the underlying HTML as well.

I'd like to reiterate my point that, as far as I can tell, the make
statement won't actually work for creating HTML in all but the most
trivial of cases. Consider:

with HtmlDocument("Title Here") as doc:
with doc.element("body"):
with doc.element("h1"):
doc.text("An ordered list")
with doc.element("ol"): # Ordered list
for value in some_list:
doc.listitem(value)

If I try to translate this to make syntax, I get into trouble. I end
up with 'value' getting set as an element over and over again. Not at
all what I want! I suppose you could filter your expression so that
only things that subtype some marker class get added, but that's
piling weirdness on top of confusion; and good sign that the whole
idea is better off abandoned.

-tim



Apr 15 '06 #20

P: n/a
Steven Bethard wrote:
Rob Williscroft wrote:
I don't know wether this has been suggested or not, but what about def:

def namespace ns:
x = 1

def type blah(object):
pass

def property x:
def get():
return ns.x


I think that's probably a bad idea because it would make people think
that the statement acts like a function definition, when it actually
acts like a class definition.


maybe this could be marked with an appropriate decorator ?

@namespace(mytype)
def ns(base1,base2) :
...

the decorator could take the function object apart, recover the bases
arguments, run the code with a referenced local dict...

hum, since in 2.4 exec allows a dict-like object as locals, it should
even be possible to hack together a pretty concise hierarchical xml
builder syntax embedded in current python - using neither the 'with' nor
the 'make' statement, but simply defs ! Note that only the root of the
(sub)tree would need to be a decorated "def" since embedded defs could
then be caught through the locals pseudo-dict.

Looks possible... at a first glance, the one thing that's unclear (to
me) is how to deal with closure variables. To learn more, my tendency
would be to launch a challenge :

"Simulate function call and execution using an exec statement, as
precisely as possible"

I'll repeat that question in another thread...

Best, az.
Apr 16 '06 #21

P: n/a
?

i really liked it
-tomer

Apr 16 '06 #22

P: n/a
Tim Hochberg wrote:
Tim Hochberg wrote:
I don't think that's correct. I think that with a suitably designed
HtmlDocument object, the following should be possible:

with HtmlDocument("Title") as doc:
with doc.element("body"):
doc.text("before first h1")
with doc.element("h1", style="first"):
doc.text("first h1")
# I don't understand the point of tail, but you could do that too
doc.text("after first h1")
with doc.element("h1", style="second"):
doc.text("second h1")
doc.text("after second h1")

Here's code to do this. It would be probably be better to use elment
tree or some such instead of pushing out the HTML directly, but this
should get the idea across (testing using 2.5a1):

[snip]

Thanks, that's great! If you don't mind, I'm going to steal your code
for the PEP. I think it makes a pretty good case against expanding the
statement semantics to include customizing the dict in which the code is
executed.

STeVe
Apr 16 '06 #23

P: n/a
> I think this PEP is going off the rails. It's primary virtue was that it
was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

And it doesn't even do that. What's wrong with "class Foo:
__metaclass__ = blah"? Two lines of code, and the double underscores
indicate something special is happening.

What I would most like to see is 'type' become the default metaclass
without having to type wait for Python 3000 or clutter the code with a
soon-to-be-redundant "(object)" base class. That would obviate my main
use of __metaclass__. How about "from __future__ import
classic_classes" for those few programs that really need old-style
classes?

Apr 18 '06 #24

P: n/a
Mike Orr wrote:
I think this PEP is going off the rails. It's primary virtue was that it

was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

And it doesn't even do that. What's wrong with "class Foo:
__metaclass__ = blah"? Two lines of code, and the double underscores
indicate something special is happening.


I think you're missing the point somewhat. The real point isn't to
make using metaclasses easier; it's to let the useful semantics of the
class statement be used for things that aren't classes.

Example: I can define the following "metaclass":

def PropertyMaker(name,bases,pdict):
fget = pdict.get("get",None)
fset = pdict.get("set",None)
fdel = pdict.get("delete",None)
doc = pdict.get("__doc__",None)
return property(fget,fset,fdel,doc)

Then, I could define a property inside some class definition like this:

class some_attribute:
__metaclass__ = PropertyMaker
def get(self):
whatever
def set(self,value):
whatever

But the thing is, if I did that, I'd be lying bastard. I'd be using
the class statement and the __metaclass__ property; however, the object
I'm creating is not a class (it's a property), and the thing I'm
assigning to __metaclass__ is not a metaclass (it's a factory
function). With the make statement, I could instead write:

make property some_attribute:
def get(self):
# etc.

Then I'm not lying about it, and I'm using a more straightforward
syntax.

If this proposal were just about metaclasses, I agree that wouldn't be
important enough to justify a new statement. Metaclasses aren't too
common, and are generally used by experts who don't need the
straightforwardness the make statement would provide.

But, properties, dicts, and other things could benefit from some of the
semantics the class statement, and with the make statement, the average
user could take advantage of that without having to worry about all
this circumlocative metaclass hackiness.
Carl Banks

Apr 18 '06 #25

P: n/a
Carl Banks wrote:
Mike Orr wrote:
I think this PEP is going off the rails. It's primary virtue was that it
was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

And it doesn't even do that. What's wrong with "class Foo:
__metaclass__ = blah"? Two lines of code, and the double underscores
indicate something special is happening.

I think you're missing the point somewhat. The real point isn't to
make using metaclasses easier; it's to let the useful semantics of the
class statement be used for things that aren't classes.


I can see how you might get the impression from the above paragraph, but
you'd be wrong.


Example: I can define the following "metaclass":

def PropertyMaker(name,bases,pdict):
fget = pdict.get("get",None)
fset = pdict.get("set",None)
fdel = pdict.get("delete",None)
doc = pdict.get("__doc__",None)
return property(fget,fset,fdel,doc)

Then, I could define a property inside some class definition like this:

class some_attribute:
__metaclass__ = PropertyMaker
def get(self):
whatever
def set(self,value):
whatever

But the thing is, if I did that, I'd be lying bastard. I'd be using
the class statement and the __metaclass__ property; however, the object
I'm creating is not a class (it's a property), and the thing I'm
assigning to __metaclass__ is not a metaclass (it's a factory
function). With the make statement, I could instead write:

make property some_attribute:
def get(self):
# etc.

Then I'm not lying about it, and I'm using a more straightforward
syntax.

If this proposal were just about metaclasses, I agree that wouldn't be
important enough to justify a new statement. Metaclasses aren't too
common, and are generally used by experts who don't need the
straightforwardness the make statement would provide.

But, properties, dicts, and other things could benefit from some of the
semantics the class statement, and with the make statement, the average
user could take advantage of that without having to worry about all
this circumlocative metaclass hackiness.


Here you've missed the point of my post. The post itself was not all
that clear, I admit, but had you read the subsequent followups, it would
have been clear that I wasn't arguing against the utility of the
statement (nor was I arguing for it), I was arguing against complicating
it for a useless use case. In particular making the namespace associated
with make statement into some sort of quasi namespace in order to
support the generating of HTML seems foolish for two reasons. First, it
doesn't actually work in any but the most trivial of cases. Second,
there is an existing syntax (as of 2.5) that can fill the same roll,
only it actually works, specifically the 'with' statement.

Regards,

-tim

Apr 18 '06 #26

P: n/a

Tim Hochberg wrote:
Carl Banks wrote:
Mike Orr wrote:
I think this PEP is going off the rails. It's primary virtue was that it

was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

And it doesn't even do that. What's wrong with "class Foo:
__metaclass__ = blah"? Two lines of code, and the double underscores
indicate something special is happening.

I think you're missing the point somewhat. The real point isn't to
make using metaclasses easier; it's to let the useful semantics of the
class statement be used for things that aren't classes.


I can see how you might get the impression from the above paragraph, but
you'd be wrong.


???
From the above post, I got the impression that it was Mike Orr that

wrote it, not you. If you and he are really the same person, you must
admit I would have no reasonable way to get any other impression. :)

No really, are you sure I was replying to what you think I was replying
to? I totally agree with you about the XML thing; it'd be a terrible
misuse of the make statement. But the post I responded to had nothing
to do with that.
Carl Banks

Apr 18 '06 #27

P: n/a
Carl Banks wrote:
Tim Hochberg wrote:
Carl Banks wrote:
Mike Orr wrote:
>I think this PEP is going off the rails. It's primary virtue was that it

was a simpler, clearer way to write:

class Foo(args):
__metaclass__ = some_metaclass
#...

And it doesn't even do that. What's wrong with "class Foo:
__metaclass__ = blah"? Two lines of code, and the double underscores
indicate something special is happening.
I think you're missing the point somewhat. The real point isn't to
make using metaclasses easier; it's to let the useful semantics of the
class statement be used for things that aren't classes.


I can see how you might get the impression from the above paragraph, but
you'd be wrong.

???
From the above post, I got the impression that it was Mike Orr that

wrote it, not you. If you and he are really the same person, you must
admit I would have no reasonable way to get any other impression. :)

No really, are you sure I was replying to what you think I was replying
to? I totally agree with you about the XML thing; it'd be a terrible
misuse of the make statement. But the post I responded to had nothing
to do with that.

My bad. I had a stack overflow or something when reading the nesting of
the post and missed who was replying to what.

Sorry,

-tim

Apr 18 '06 #28

P: n/a

Carl> class some_attribute:
Carl> __metaclass__ = PropertyMaker
Carl> def get(self):
Carl> whatever
Carl> def set(self,value):
Carl> whatever

Carl> But the thing is, if I did that, I'd be lying bastard.... With
Carl> the make statement, I could instead write:

Carl> make property some_attribute:
Carl> def get(self):
Carl> # etc.

Carl> Then I'm not lying about it, and I'm using a more straightforward
Carl> syntax.

I agree. For the specific example of creating properties, you could
probably dream up some other syntax, but I suspect this notion will pop up
again. Even if you comment the heck out of a lying class definition, tools
like pylint and pychecker will think you're creating a class anyway and
incorrectly apply their class heuristics to your whatever-it-is.

Skip
Apr 18 '06 #29

This discussion thread is closed

Replies have been disabled for this discussion.