reSTify PEP 363 (#322)
This commit is contained in:
parent
e889fa82a5
commit
7f68262609
61
pep-0363.txt
61
pep-0363.txt
|
@ -5,22 +5,23 @@ Last-Modified: $Date$
|
|||
Author: Ben North <ben@redfrontdoor.org>
|
||||
Status: Rejected
|
||||
Type: Standards Track
|
||||
Content-Type: text/plain
|
||||
Content-Type: text/x-rst
|
||||
Created: 29-Jan-2007
|
||||
Post-History: 12-Feb-2007
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
Dynamic attribute access is currently possible using the "getattr"
|
||||
and "setattr" builtins. The present PEP suggests a new syntax to
|
||||
make such access easier, allowing the coder for example to write
|
||||
make such access easier, allowing the coder for example to write::
|
||||
|
||||
x.('foo_%d' % n) += 1
|
||||
|
||||
z = y.('foo_%d' % n).('bar_%s' % s)
|
||||
|
||||
instead of
|
||||
instead of::
|
||||
|
||||
attr_name = 'foo_%d' % n
|
||||
setattr(x, attr_name, getattr(x, attr_name) + 1)
|
||||
|
@ -29,9 +30,10 @@ Abstract
|
|||
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
Dictionary access and indexing both have a friendly invocation
|
||||
syntax: instead of x.__getitem__(12) the coder can write x[12].
|
||||
syntax: instead of ``x.__getitem__(12)`` the coder can write ``x[12]``.
|
||||
This also allows the use of subscripted elements in an augmented
|
||||
assignment, as in "x[12] += 1". The present proposal brings this
|
||||
ease-of-use to dynamic attribute access too.
|
||||
|
@ -39,20 +41,20 @@ Rationale
|
|||
Attribute access is currently possible in two ways:
|
||||
|
||||
* When the attribute name is known at code-writing time, the
|
||||
".NAME" trailer can be used, as in
|
||||
".NAME" trailer can be used, as in::
|
||||
|
||||
x.foo = 42
|
||||
y.bar += 100
|
||||
|
||||
* When the attribute name is computed dynamically at run-time, the
|
||||
"getattr" and "setattr" builtins must be used:
|
||||
"getattr" and "setattr" builtins must be used::
|
||||
|
||||
x = getattr(y, 'foo_%d' % n)
|
||||
setattr(z, 'bar_%s' % s, 99)
|
||||
|
||||
The "getattr" builtin also allows the coder to specify a default
|
||||
value to be returned in the event that the object does not have
|
||||
an attribute of the given name:
|
||||
an attribute of the given name::
|
||||
|
||||
x = getattr(y, 'foo_%d' % n, 0)
|
||||
|
||||
|
@ -60,7 +62,7 @@ Rationale
|
|||
"x.(expr)" --- with examples given in the Abstract above.
|
||||
|
||||
(The new syntax could also allow the provision of a default value in
|
||||
the "get" case, as in:
|
||||
the "get" case, as in::
|
||||
|
||||
x = y.('foo_%d' % n, None)
|
||||
|
||||
|
@ -69,20 +71,21 @@ Rationale
|
|||
"Discussion" section below includes opinions specifically on the
|
||||
2-argument extension.)
|
||||
|
||||
Finally, the new syntax can be used with the "del" statement, as in
|
||||
Finally, the new syntax can be used with the "del" statement, as in::
|
||||
|
||||
del x.(attr_name)
|
||||
|
||||
|
||||
Impact On Existing Code
|
||||
=======================
|
||||
|
||||
The proposed new syntax is not currently valid, so no existing
|
||||
well-formed programs have their meaning altered by this proposal.
|
||||
|
||||
Across all "*.py" files in the 2.5 distribution, there are around
|
||||
Across all "\*.py" files in the 2.5 distribution, there are around
|
||||
600 uses of "getattr", "setattr" or "delattr". They break down as
|
||||
follows (figures have some room for error because they were
|
||||
arrived at by partially-manual inspection):
|
||||
arrived at by partially-manual inspection)::
|
||||
|
||||
c.300 uses of plain "getattr(x, attr_name)", which could be
|
||||
replaced with the new syntax;
|
||||
|
@ -113,24 +116,25 @@ Impact On Existing Code
|
|||
|
||||
c.10 uses of "delattr", which could use the new syntax.
|
||||
|
||||
As examples, the line
|
||||
As examples, the line::
|
||||
|
||||
setattr(self, attr, change_root(self.root, getattr(self, attr)))
|
||||
|
||||
from Lib/distutils/command/install.py could be rewritten
|
||||
from Lib/distutils/command/install.py could be rewritten::
|
||||
|
||||
self.(attr) = change_root(self.root, self.(attr))
|
||||
|
||||
and the line
|
||||
and the line::
|
||||
|
||||
setattr(self, method_name, getattr(self.metadata, method_name))
|
||||
|
||||
from Lib/distutils/dist.py could be rewritten
|
||||
from Lib/distutils/dist.py could be rewritten::
|
||||
|
||||
self.(method_name) = self.metadata.(method_name)
|
||||
|
||||
|
||||
Performance Impact
|
||||
==================
|
||||
|
||||
Initial pystone measurements are inconclusive, but suggest there may
|
||||
be a performance penalty of around 1% in the pystones score with the
|
||||
|
@ -143,19 +147,21 @@ Performance Impact
|
|||
|
||||
|
||||
Error Cases
|
||||
===========
|
||||
|
||||
Only strings are permitted as attribute names, so for instance the
|
||||
following error is produced:
|
||||
following error is produced::
|
||||
|
||||
>>> x.(99) = 8
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: attribute name must be string, not 'int'
|
||||
|
||||
This is handled by the existing PyObject_GetAttr function.
|
||||
This is handled by the existing ``PyObject_GetAttr`` function.
|
||||
|
||||
|
||||
Draft Implementation
|
||||
====================
|
||||
|
||||
A draft implementation adds a new alternative to the "trailer"
|
||||
clause in Grammar/Grammar; a new AST type, "DynamicAttribute" in
|
||||
|
@ -163,21 +169,22 @@ Draft Implementation
|
|||
compile.c, and three new opcodes (load/store/del) with
|
||||
accompanying changes to opcode.h and ceval.c. The patch consists
|
||||
of c.180 additional lines in the core code, and c.100 additional
|
||||
lines of tests. It is available as sourceforge patch #1657573 [1].
|
||||
lines of tests. It is available as sourceforge patch #1657573 [1]_.
|
||||
|
||||
|
||||
Mailing Lists Discussion
|
||||
========================
|
||||
|
||||
Initial posting of this PEP in draft form was to python-ideas on
|
||||
20070209 [2], and the response was generally positive. The PEP was
|
||||
then posted to python-dev on 20070212 [3], and an interesting
|
||||
20070209 [2]_, and the response was generally positive. The PEP was
|
||||
then posted to python-dev on 20070212 [3]_, and an interesting
|
||||
discussion ensued. A brief summary:
|
||||
|
||||
Initially, there was reasonable (but not unanimous) support for the
|
||||
idea, although the precise choice of syntax had a more mixed
|
||||
reception. Several people thought the "." would be too easily
|
||||
overlooked, with the result that the syntax could be confused with a
|
||||
method/function call. A few alternative syntaxes were suggested:
|
||||
method/function call. A few alternative syntaxes were suggested::
|
||||
|
||||
obj.(foo)
|
||||
obj.[foo]
|
||||
|
@ -201,7 +208,7 @@ Mailing Lists Discussion
|
|||
|
||||
Instead of new syntax, a new "wrapper class" was proposed, with the
|
||||
following specification / conceptual implementation suggested by
|
||||
Martin von Loewis:
|
||||
Martin von Löwis::
|
||||
|
||||
class attrs:
|
||||
def __init__(self, obj):
|
||||
|
@ -226,22 +233,24 @@ Mailing Lists Discussion
|
|||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
[1] Sourceforge patch #1657573
|
||||
.. [1] Sourceforge patch #1657573
|
||||
http://sourceforge.net/tracker/index.php?func=detail&aid=1657573&group_id=5470&atid=305470
|
||||
|
||||
[2] https://mail.python.org/pipermail/python-ideas/2007-February/000210.html
|
||||
.. [2] https://mail.python.org/pipermail/python-ideas/2007-February/000210.html
|
||||
and following posts
|
||||
|
||||
[3] https://mail.python.org/pipermail/python-dev/2007-February/070939.html
|
||||
.. [3] https://mail.python.org/pipermail/python-dev/2007-February/070939.html
|
||||
and following posts
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
|
|
Loading…
Reference in New Issue