251 lines
7.8 KiB
Plaintext
251 lines
7.8 KiB
Plaintext
PEP: 232
|
||
Title: Function Attributes
|
||
Version: $Revision$
|
||
Author: barry@zope.com (Barry A. Warsaw)
|
||
Status: Final
|
||
Type: Standards Track
|
||
Created: 02-Dec-2000
|
||
Python-Version: 2.1
|
||
Post-History: 20-Feb-2001
|
||
|
||
|
||
Introduction
|
||
|
||
This PEP describes an extension to Python, adding attribute
|
||
dictionaries to functions and methods. This PEP tracks the status
|
||
and ownership of this feature. It contains a description of the
|
||
feature and outlines changes necessary to support the feature.
|
||
This PEP summarizes discussions held in mailing list forums, and
|
||
provides URLs for further information, where appropriate. The CVS
|
||
revision history of this file contains the definitive historical
|
||
record.
|
||
|
||
|
||
Background
|
||
|
||
Functions already have a number of attributes, some of which are
|
||
writable, e.g. func_doc, a.k.a. func.__doc__. func_doc has the
|
||
interesting property that there is special syntax in function (and
|
||
method) definitions for implicitly setting the attribute. This
|
||
convenience has been exploited over and over again, overloading
|
||
docstrings with additional semantics.
|
||
|
||
For example, John Aycock has written a system where docstrings are
|
||
used to define parsing rules[1]. Zope's ZPublisher ORB[2] uses
|
||
docstrings to signal "publishable" methods, i.e. methods that can
|
||
be called through the web.
|
||
|
||
The problem with this approach is that the overloaded semantics
|
||
may conflict with each other. For example, if we wanted to add a
|
||
doctest unit test to a Zope method that should not be publishable
|
||
through the web.
|
||
|
||
|
||
Proposal
|
||
|
||
This proposal adds a new dictionary to function objects, called
|
||
func_dict (a.k.a. __dict__). This dictionary can be set and get
|
||
using ordinary attribute set and get syntax.
|
||
|
||
Methods also gain `getter' syntax, and they currently access the
|
||
attribute through the dictionary of the underlying function
|
||
object. It is not possible to set attributes on bound or unbound
|
||
methods, except by doing so explicitly on the underlying function
|
||
object. See the `Future Directions' discussion below for
|
||
approaches in subsequent versions of Python.
|
||
|
||
A function object's __dict__ can also be set, but only to a
|
||
dictionary object or None (e.g. setting __dict__ to UserDict
|
||
raises a TypeError). Deleting a function's __dict__ attribute is
|
||
equivalent to setting it to None. If no function attributes have
|
||
ever been set, the function's __dict__ will be None.
|
||
|
||
|
||
Examples
|
||
|
||
Here are some examples of what you can do with this feature.
|
||
|
||
def a():
|
||
pass
|
||
|
||
a.publish = 1
|
||
a.unittest = '''...'''
|
||
|
||
if a.publish:
|
||
print a()
|
||
|
||
if hasattr(a, 'unittest'):
|
||
testframework.execute(a.unittest)
|
||
|
||
class C:
|
||
def a(self):
|
||
'just a docstring'
|
||
a.publish = 1
|
||
|
||
c = C()
|
||
if c.a.publish:
|
||
publish(c.a())
|
||
|
||
|
||
Other Uses
|
||
|
||
Paul Prescod enumerated a bunch of other uses:
|
||
|
||
http://mail.python.org/pipermail/python-dev/2000-April/003364.html
|
||
|
||
|
||
Future Directions
|
||
|
||
Here are a number of future directions to consider. Any adoption
|
||
of these ideas would require a new PEP, which referenced this one,
|
||
and would have to be targeted at a Python version subsequent to
|
||
the 2.1 release.
|
||
|
||
- A previous version of this PEP allowed for both setter and
|
||
getter of attributes on unbound methods, and only getter on
|
||
bound methods. A number of problems were discovered with this
|
||
policy.
|
||
|
||
Because method attributes were stored in the underlying
|
||
function, this caused several potentially surprising results:
|
||
|
||
class C:
|
||
def a(self): pass
|
||
|
||
c1 = C()
|
||
c2 = C()
|
||
c1.a.publish = 1
|
||
# c2.a.publish would now be == 1 also!
|
||
|
||
Because a change to `a' bound c1 also caused a change to `a'
|
||
bound to c2, setting of attributes on bound methods was
|
||
disallowed. However, even allowing setting of attributes on
|
||
unbound methods has its ambiguities:
|
||
|
||
class D(C): pass
|
||
class E(C): pass
|
||
|
||
D.a.publish = 1
|
||
# E.a.publish would now be == 1 also!
|
||
|
||
For this reason, the current PEP disallows setting attributes on
|
||
either bound or unbound methods, but does allow for getting
|
||
attributes on either -- both return the attribute value on the
|
||
underlying function object.
|
||
|
||
A future PEP might propose to implement setting (bound or
|
||
unbound) method attributes by setting attributes on the instance
|
||
or class, using special naming conventions. I.e.
|
||
|
||
class C:
|
||
def a(self): pass
|
||
|
||
C.a.publish = 1
|
||
C.__a_publish__ == 1 # true
|
||
|
||
c = C()
|
||
c.a.publish = 2
|
||
c.__a_publish__ == 2 # true
|
||
|
||
d = C()
|
||
d.__a_publish__ == 1 # true
|
||
|
||
Here, a lookup on the instance would look to the instance's
|
||
dictionary first, followed by a lookup on the class's
|
||
dictionary, and finally a lookup on the function object's
|
||
dictionary.
|
||
|
||
- Currently, Python supports function attributes only on Python
|
||
functions (i.e. those that are written in Python, not those that
|
||
are built-in). Should it be worthwhile, a separate patch can be
|
||
crafted that will add function attributes to built-ins.
|
||
|
||
- __doc__ is the only function attribute that currently has
|
||
syntactic support for conveniently setting. It may be
|
||
worthwhile to eventually enhance the language for supporting
|
||
easy function attribute setting. Here are some syntaxes
|
||
suggested by PEP reviewers:
|
||
|
||
def a {
|
||
'publish' : 1,
|
||
'unittest': '''...''',
|
||
}
|
||
(args):
|
||
# ...
|
||
|
||
def a(args):
|
||
"""The usual docstring."""
|
||
{'publish' : 1,
|
||
'unittest': '''...''',
|
||
# etc.
|
||
}
|
||
|
||
def a(args) having (publish = 1):
|
||
# see reference [3]
|
||
pass
|
||
|
||
The BDFL is currently against any such special syntactic support
|
||
for setting arbitrary function attributes. Any syntax proposals
|
||
would have to be outlined in new PEPs.
|
||
|
||
|
||
Dissenting Opinion
|
||
|
||
When this was discussed on the python-dev mailing list in April
|
||
2000, a number of dissenting opinions were voiced. For
|
||
completeness, the discussion thread starts here:
|
||
|
||
http://mail.python.org/pipermail/python-dev/2000-April/003361.html
|
||
|
||
The dissenting arguments appear to fall under the following
|
||
categories:
|
||
|
||
- no clear purpose (what does it buy you?)
|
||
- other ways to do it (e.g. mappings as class attributes)
|
||
- useless until syntactic support is included
|
||
|
||
Countering some of these arguments is the observation that with
|
||
vanilla Python 2.0, __doc__ can in fact be set to any type of
|
||
object, so some semblance of writable function attributes are
|
||
already feasible. But that approach is yet another corruption of
|
||
__doc__.
|
||
|
||
And while it is of course possible to add mappings to class
|
||
objects (or in the case of function attributes, to the function's
|
||
module), it is more difficult and less obvious how to extract the
|
||
attribute values for inspection.
|
||
|
||
Finally, it may be desirable to add syntactic support, much the
|
||
same way that __doc__ syntactic support exists. This can be
|
||
considered separately from the ability to actually set and get
|
||
function attributes.
|
||
|
||
|
||
Reference Implementation
|
||
|
||
This PEP has been accepted and the implementation has been
|
||
integrated into Python 2.1.
|
||
|
||
|
||
References
|
||
|
||
[1] Aycock, "Compiling Little Languages in Python",
|
||
http://www.foretec.com/python/workshops/1998-11/proceedings/papers/aycock-little/aycock-little.html
|
||
|
||
[2] http://classic.zope.org:8080/Documentation/Reference/ORB
|
||
|
||
[3] Hudson, Michael, SourceForge patch implementing this syntax,
|
||
http://sourceforge.net/tracker/index.php?func=detail&aid=403441&group_id=5470&atid=305470
|
||
|
||
|
||
Copyright
|
||
|
||
This document has been placed in the Public Domain.
|
||
|
||
|
||
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
End:
|