From 7f682626096b65e3f8b1cb6e98170e6ddd71f5c1 Mon Sep 17 00:00:00 2001 From: Huang Huang Date: Sat, 12 Aug 2017 02:41:01 +0800 Subject: [PATCH] reSTify PEP 363 (#322) --- pep-0363.txt | 325 ++++++++++++++++++++++++++------------------------- 1 file changed, 167 insertions(+), 158 deletions(-) diff --git a/pep-0363.txt b/pep-0363.txt index 52647779d..477e1b0ea 100644 --- a/pep-0363.txt +++ b/pep-0363.txt @@ -5,247 +5,256 @@ Last-Modified: $Date$ Author: Ben North 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 +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:: - x.('foo_%d' % n) += 1 + x.('foo_%d' % n) += 1 - z = y.('foo_%d' % n).('bar_%s' % s) + 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) + attr_name = 'foo_%d' % n + setattr(x, attr_name, getattr(x, attr_name) + 1) - z = getattr(getattr(y, 'foo_%d' % n), 'bar_%s' % s) + z = getattr(getattr(y, 'foo_%d' % n), 'bar_%s' % s) Rationale +========= - Dictionary access and indexing both have a friendly invocation - 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. +Dictionary access and indexing both have a friendly invocation +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. - Attribute access is currently possible in two ways: +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 +* When the attribute name is known at code-writing time, the + ".NAME" trailer can be used, as in:: - x.foo = 42 - y.bar += 100 + x.foo = 42 + y.bar += 100 - * When the attribute name is computed dynamically at run-time, the - "getattr" and "setattr" builtins must be used: +* When the attribute name is computed dynamically at run-time, the + "getattr" and "setattr" builtins must be used:: - x = getattr(y, 'foo_%d' % n) - setattr(z, 'bar_%s' % s, 99) + 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: + 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:: - x = getattr(y, 'foo_%d' % n, 0) + x = getattr(y, 'foo_%d' % n, 0) - This PEP describes a new syntax for dynamic attribute access --- - "x.(expr)" --- with examples given in the Abstract above. +This PEP describes a new syntax for dynamic attribute access --- +"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 new syntax could also allow the provision of a default value in +the "get" case, as in:: - x = y.('foo_%d' % n, None) + x = y.('foo_%d' % n, None) - This 2-argument form of dynamic attribute access would not be - permitted as the target of an (augmented or normal) assignment. The - "Discussion" section below includes opinions specifically on the - 2-argument extension.) +This 2-argument form of dynamic attribute access would not be +permitted as the target of an (augmented or normal) assignment. The +"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) + 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. +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 - 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): +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):: - c.300 uses of plain "getattr(x, attr_name)", which could be - replaced with the new syntax; + c.300 uses of plain "getattr(x, attr_name)", which could be + replaced with the new syntax; - c.150 uses of the 3-argument form, i.e., with the default - value; these could be replaced with the 2-argument form - of the new syntax (the cases break down into c.125 cases - where the attribute name is a literal string, and c.25 - where it's only known at run-time); + c.150 uses of the 3-argument form, i.e., with the default + value; these could be replaced with the 2-argument form + of the new syntax (the cases break down into c.125 cases + where the attribute name is a literal string, and c.25 + where it's only known at run-time); - c.5 uses of the 2-argument form with a literal string - attribute name, which I think could be replaced with the - standard "x.attribute" syntax; + c.5 uses of the 2-argument form with a literal string + attribute name, which I think could be replaced with the + standard "x.attribute" syntax; - c.120 uses of setattr, of which 15 use getattr to find the - new value; all could be replaced with the new syntax, - the 15 where getattr is also involved would show a - particular increase in clarity; + c.120 uses of setattr, of which 15 use getattr to find the + new value; all could be replaced with the new syntax, + the 15 where getattr is also involved would show a + particular increase in clarity; - c.5 uses which would have to stay as "getattr" because they - are calls of a variable named "getattr" whose default - value is the builtin "getattr"; + c.5 uses which would have to stay as "getattr" because they + are calls of a variable named "getattr" whose default + value is the builtin "getattr"; - c.5 uses of the 2-argument form, inside a try/except block - which catches AttributeError and uses a default value - instead; these could use 2-argument form of the new - syntax; + c.5 uses of the 2-argument form, inside a try/except block + which catches AttributeError and uses a default value + instead; these could use 2-argument form of the new + syntax; - c.10 uses of "delattr", which could use the new syntax. + 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))) + 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)) + self.(attr) = change_root(self.root, self.(attr)) - and the line +and the line:: - setattr(self, method_name, getattr(self.metadata, method_name)) + 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) + 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 - patched version. One suggestion is that this is because the longer - main loop in ceval.c hurts the cache behaviour, but this has not - been confirmed. +Initial pystone measurements are inconclusive, but suggest there may +be a performance penalty of around 1% in the pystones score with the +patched version. One suggestion is that this is because the longer +main loop in ceval.c hurts the cache behaviour, but this has not +been confirmed. - On the other hand, measurements suggest a speed-up of around 40--45% - for dynamic attribute access. +On the other hand, measurements suggest a speed-up of around 40--45% +for dynamic attribute access. Error Cases +=========== - Only strings are permitted as attribute names, so for instance the - following error is produced: +Only strings are permitted as attribute names, so for instance the +following error is produced:: - >>> x.(99) = 8 - Traceback (most recent call last): - File "", line 1, in - TypeError: attribute name must be string, not 'int' + >>> x.(99) = 8 + Traceback (most recent call last): + File "", line 1, in + 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 - Python.asdl, with accompanying changes to symtable.c, ast.c, and - 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]. +A draft implementation adds a new alternative to the "trailer" +clause in Grammar/Grammar; a new AST type, "DynamicAttribute" in +Python.asdl, with accompanying changes to symtable.c, ast.c, and +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]_. 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 - discussion ensued. A brief summary: +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 +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: +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:: - obj.(foo) - obj.[foo] - obj.{foo} - obj{foo} - obj.*foo - obj->foo - obj<-foo - obj@[foo] - obj.[[foo]] + obj.(foo) + obj.[foo] + obj.{foo} + obj{foo} + obj.*foo + obj->foo + obj<-foo + obj@[foo] + obj.[[foo]] - with "obj.[foo]" emerging as the preferred one. In this initial - discussion, the two-argument form was universally disliked, so it - was to be taken out of the PEP. +with "obj.[foo]" emerging as the preferred one. In this initial +discussion, the two-argument form was universally disliked, so it +was to be taken out of the PEP. - Discussion then took a step back to whether this particular feature - provided enough benefit to justify new syntax. As well as requiring - coders to become familiar with the new syntax, there would also be - the problem of backward compatibility --- code using the new syntax - would not run on older pythons. +Discussion then took a step back to whether this particular feature +provided enough benefit to justify new syntax. As well as requiring +coders to become familiar with the new syntax, there would also be +the problem of backward compatibility --- code using the new syntax +would not run on older pythons. - Instead of new syntax, a new "wrapper class" was proposed, with the - following specification / conceptual implementation suggested by - Martin von Loewis: +Instead of new syntax, a new "wrapper class" was proposed, with the +following specification / conceptual implementation suggested by +Martin von Löwis:: - class attrs: - def __init__(self, obj): - self.obj = obj - def __getitem__(self, name): - return getattr(self.obj, name) - def __setitem__(self, name, value): - return setattr(self.obj, name, value) - def __delitem__(self, name): - return delattr(self, name) - def __contains__(self, name): - return hasattr(self, name) + class attrs: + def __init__(self, obj): + self.obj = obj + def __getitem__(self, name): + return getattr(self.obj, name) + def __setitem__(self, name, value): + return setattr(self.obj, name, value) + def __delitem__(self, name): + return delattr(self, name) + def __contains__(self, name): + return hasattr(self, name) - This was considered a cleaner and more elegant solution to the - original problem. (Another suggestion was a mixin class providing - dictionary-style access to an object's attributes.) +This was considered a cleaner and more elegant solution to the +original problem. (Another suggestion was a mixin class providing +dictionary-style access to an object's attributes.) - The decision was made that the present PEP did not meet the burden - of proof for the introduction of new syntax, a view which had been - put forward by some from the beginning of the discussion. The - wrapper class idea was left open as a possibility for a future PEP. +The decision was made that the present PEP did not meet the burden +of proof for the introduction of new syntax, a view which had been +put forward by some from the beginning of the discussion. The +wrapper class idea was left open as a possibility for a future PEP. References +========== - [1] Sourceforge patch #1657573 - http://sourceforge.net/tracker/index.php?func=detail&aid=1657573&group_id=5470&atid=305470 +.. [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 - and following posts +.. [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 - and following posts +.. [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. +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: +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: