Arbitrary attributes on funcs and methods
A number of people have played FAST and loose with function and method docstrings, including John Aycock[1], Zope's ORB[2]. Docstrings are handy because they are the one attribute on funcs and methods that are easily writable. But as more people overload the semantics for docstrings, we'll get collisions. I've had a number of discussions with folks about adding attribute dictionaries to functions and methods so that you can essentially add any attribute. Namespaces are one honking great idea -- let's do more of those! Below is a very raw set of patches to add an attribute dictionary to funcs and methods. It's only been minimally tested, but if y'all like the idea, I'll clean it up, sanity check the memory management, and post the changes to patches@python.org. Here's some things you can do: -------------------- snip snip -------------------- Python 1.6a2 (#10, Apr 10 2000, 11:27:59) [GCC 2.8.1] on sunos5 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
def a(): pass ... a.publish = 1 a.publish 1 a.__doc__ a.__doc__ = 'a doc string' a.__doc__ 'a doc string' a.magic_string = a.__doc__ a.magic_string 'a doc string' dir(a) ['__doc__', '__name__', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name', 'magic_string', 'publish'] class F: ... def a(self): pass ... f = F() f.a.publish Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: publish f.a.publish = 1 f.a.publish 1 f.a.__doc__ f.a.__doc__ = 'another doc string' f.a.__doc__ 'another doc string' f.a.magic_string = f.a.__doc__ f.a.magic_string 'another doc string' dir(f.a) ['__dict__', '__doc__', '__name__', 'im_class', 'im_func', 'im_self', 'magic_string', 'publish']
-------------------- snip snip --------------------
-Barry [1] Aycock, "Compiling Little Languages in Python", http://www.foretec.com/python/workshops/1998-11/proceedings/papers/aycock-li... [2] http://classic.zope.org:8080/Documentation/Reference/ORB P.S. I promised to add a little note about setattr and getattr vs. setattro and getattro. There's very little documentation about the differences, and searching on python.org doesn't seem to turn up anything. The differences are simple. setattr/getattr take a char* argument naming the attribute to change, while setattro/getattro take a PyObject* (hence the trailing `o' -- for Object). This stuff should get documented in the C API, but at least now, it'll turn up in a SIG search. :) -------------------- snip snip -------------------- Index: funcobject.h =================================================================== RCS file: /projects/cvsroot/python/dist/src/Include/funcobject.h,v retrieving revision 2.16 diff -c -r2.16 funcobject.h *** funcobject.h 1998/12/04 18:48:02 2.16 --- funcobject.h 2000/04/07 21:30:40 *************** *** 44,49 **** --- 44,50 ---- PyObject *func_defaults; PyObject *func_doc; PyObject *func_name; + PyObject *func_dict; } PyFunctionObject; extern DL_IMPORT(PyTypeObject) PyFunction_Type; Index: classobject.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Objects/classobject.c,v retrieving revision 2.84 diff -c -r2.84 classobject.c *** classobject.c 2000/04/10 13:03:19 2.84 --- classobject.c 2000/04/10 15:27:15 *************** *** 1550,1577 **** /* Dummies that are not handled by getattr() except for __members__ */ {"__doc__", T_INT, 0}, {"__name__", T_INT, 0}, {NULL} /* Sentinel */ }; static PyObject * instancemethod_getattr(im, name) register PyMethodObject *im; ! PyObject *name; { ! char *sname = PyString_AsString(name); ! if (sname[0] == '_') { /* Inherit __name__ and __doc__ from the callable object implementing the method */ ! if (strcmp(sname, "__name__") == 0 || ! strcmp(sname, "__doc__") == 0) ! return PyObject_GetAttr(im->im_func, name); } if (PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "instance-method attributes not accessible in restricted mode"); return NULL; } ! return PyMember_Get((char *)im, instancemethod_memberlist, sname); } static void --- 1550,1608 ---- /* Dummies that are not handled by getattr() except for __members__ */ {"__doc__", T_INT, 0}, {"__name__", T_INT, 0}, + {"__dict__", T_INT, 0}, {NULL} /* Sentinel */ }; + static int + instancemethod_setattr(im, name, v) + register PyMethodObject *im; + char *name; + PyObject *v; + { + int rtn; + + if (PyEval_GetRestricted() || + strcmp(name, "im_func") == 0 || + strcmp(name, "im_self") == 0 || + strcmp(name, "im_class") == 0) + { + PyErr_Format(PyExc_TypeError, "read-only attribute: %s", name); + return -1; + } + return PyObject_SetAttrString(im->im_func, name, v); + } + + static PyObject * instancemethod_getattr(im, name) register PyMethodObject *im; ! char *name; { ! PyObject *rtn; ! ! if (strcmp(name, "__name__") == 0 || ! strcmp(name, "__doc__") == 0) { /* Inherit __name__ and __doc__ from the callable object implementing the method */ ! return PyObject_GetAttrString(im->im_func, name); } if (PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "instance-method attributes not accessible in restricted mode"); return NULL; + } + if (strcmp(name, "__dict__") == 0) + return PyObject_GetAttrString(im->im_func, name); + + rtn = PyMember_Get((char *)im, instancemethod_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyObject_GetAttrString(im->im_func, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name); } ! return rtn; } static void *************** *** 1662,1669 **** 0, (destructor)instancemethod_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ ! 0, /*tp_getattr*/ ! 0, /*tp_setattr*/ (cmpfunc)instancemethod_compare, /*tp_compare*/ (reprfunc)instancemethod_repr, /*tp_repr*/ 0, /*tp_as_number*/ --- 1693,1700 ---- 0, (destructor)instancemethod_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ ! (getattrfunc)instancemethod_getattr, /*tp_getattr*/ ! (setattrfunc)instancemethod_setattr, /*tp_setattr*/ (cmpfunc)instancemethod_compare, /*tp_compare*/ (reprfunc)instancemethod_repr, /*tp_repr*/ 0, /*tp_as_number*/ *************** *** 1672,1678 **** (hashfunc)instancemethod_hash, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ ! (getattrofunc)instancemethod_getattr, /*tp_getattro*/ 0, /*tp_setattro*/ }; --- 1703,1709 ---- (hashfunc)instancemethod_hash, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ ! 0, /*tp_getattro*/ 0, /*tp_setattro*/ }; Index: funcobject.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Objects/funcobject.c,v retrieving revision 2.18 diff -c -r2.18 funcobject.c *** funcobject.c 1998/05/22 00:55:34 2.18 --- funcobject.c 2000/04/07 22:15:33 *************** *** 62,67 **** --- 62,68 ---- doc = Py_None; Py_INCREF(doc); op->func_doc = doc; + op->func_dict = PyDict_New(); } return (PyObject *)op; } *************** *** 133,138 **** --- 134,140 ---- {"__name__", T_OBJECT, OFF(func_name), READONLY}, {"func_defaults",T_OBJECT, OFF(func_defaults)}, {"func_doc", T_OBJECT, OFF(func_doc)}, + {"func_dict", T_OBJECT, OFF(func_dict)}, {"__doc__", T_OBJECT, OFF(func_doc)}, {NULL} /* Sentinel */ }; *************** *** 142,153 **** PyFunctionObject *op; char *name; { if (name[0] != '_' && PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "function attributes not accessible in restricted mode"); return NULL; } ! return PyMember_Get((char *)op, func_memberlist, name); } static int --- 144,167 ---- PyFunctionObject *op; char *name; { + PyObject* rtn; + if (name[0] != '_' && PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "function attributes not accessible in restricted mode"); return NULL; + } + if (strcmp(name, "__dict__") == 0) + return op->func_dict; + + rtn = PyMember_Get((char *)op, func_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyDict_GetItemString(op->func_dict, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name); } ! return rtn; } static int *************** *** 156,161 **** --- 170,177 ---- char *name; PyObject *value; { + int rtn; + if (PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "function attributes not settable in restricted mode"); *************** *** 178,185 **** } if (value == Py_None) value = NULL; } ! return PyMember_Set((char *)op, func_memberlist, name, value); } static void --- 194,214 ---- } if (value == Py_None) value = NULL; + } + else if (strcmp(name, "func_dict") == 0) { + if (value == NULL || !PyDict_Check(value)) { + PyErr_SetString( + PyExc_TypeError, + "func_dict must be set to a dict object"); + return -1; + } + } + rtn = PyMember_Set((char *)op, func_memberlist, name, value); + if (rtn < 0) { + PyErr_Clear(); + rtn = PyDict_SetItemString(op->func_dict, name, value); } ! return rtn; } static void *************** *** 191,196 **** --- 220,226 ---- Py_DECREF(op->func_name); Py_XDECREF(op->func_defaults); Py_XDECREF(op->func_doc); + Py_XDECREF(op->func_dict); PyMem_DEL(op); }
A number of people have played FAST and loose with function and method docstrings, including John Aycock[1], Zope's ORB[2]. Docstrings are handy because they are the one attribute on funcs and methods that are easily writable. But as more people overload the semantics for docstrings, we'll get collisions. I've had a number of discussions with folks about adding attribute dictionaries to functions and methods so that you can essentially add any attribute. Namespaces are one honking great idea -- let's do more of those!
Below is a very raw set of patches to add an attribute dictionary to funcs and methods. It's only been minimally tested, but if y'all like the idea, I'll clean it up, sanity check the memory management, and post the changes to patches@python.org. Here's some things you can do:
-------------------- snip snip -------------------- Python 1.6a2 (#10, Apr 10 2000, 11:27:59) [GCC 2.8.1] on sunos5 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
def a(): pass ... a.publish = 1 a.publish 1 a.__doc__ a.__doc__ = 'a doc string' a.__doc__ 'a doc string' a.magic_string = a.__doc__ a.magic_string 'a doc string' dir(a) ['__doc__', '__name__', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name', 'magic_string', 'publish'] class F: ... def a(self): pass ... f = F() f.a.publish Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: publish f.a.publish = 1 f.a.publish 1
Here I have a question. Should this really change F.a, or should it change the method bound to f only? You implement the former, but I'm not sure if those semantics are right -- if I have two instances, f1 and f2, and you change f2.a.spam, I'd be surprised if f1.a.spam got changed as well (since f1.a and f2.a are *not* the same thing -- they are not shared. f1.a.im_func and f2.a.im_func are the same thing, but f1.a and f2.a are distinct! I would suggest that you only allow setting attributes via the class or via a function. (This means that you must still implement the pass-through on method objects, but reject it if the method is bound to an instance.) --Guido van Rossum (home page: http://www.python.org/~guido/)
"GvR" == Guido van Rossum <guido@python.org> writes:
GvR> Here I have a question. Should this really change F.a, or GvR> should it change the method bound to f only? You implement GvR> the former, but I'm not sure if those semantics are right -- GvR> if I have two instances, f1 and f2, and you change f2.a.spam, GvR> I'd be surprised if f1.a.spam got changed as well (since f1.a GvR> and f2.a are *not* the same thing -- they are not shared. GvR> f1.a.im_func and f2.a.im_func are the same thing, but f1.a GvR> and f2.a are distinct! As are f1.a and f1.a! :) GvR> I would suggest that you only allow setting attributes via GvR> the class or via a function. (This means that you must still GvR> implement the pass-through on method objects, but reject it GvR> if the method is bound to an instance.) Given that, Python should probably raise a TypeError if an attempt is made to set an attribute on a bound method object. However, it should definitely succeed to /get/ an attribute on a bound method object. I'm not 100% sure that setting bound-method-attributes should be illegal, but we can be strict about it now and see if it makes sense to loosen the restriction later. Here's a candidate for Lib/test/test_methattr.py which should print a bunch of `1's. I'll post the revised diffs (taking into account GvR's and GS's suggestions) tomorrow after I've had a night to sleep on it. -Barry -------------------- snip snip -------------------- from test_support import verbose class F: def a(self): pass def b(): pass # setting attributes on functions try: b.blah except AttributeError: pass else: print 'did not get expected AttributeError' b.blah = 1 print b.blah == 1 print 'blah' in dir(b) # setting attributes on unbound methods try: F.a.blah except AttributeError: pass else: print 'did not get expected AttributeError' F.a.blah = 1 print F.a.blah == 1 print 'blah' in dir(F.a) # setting attributes on bound methods is illegal f1 = F() try: f1.a.snerp = 1 except TypeError: pass else: print 'did not get expected TypeError' # but accessing attributes on bound methods is fine print f1.a.blah print 'blah' in dir(f1.a) f2 = F() print f1.a.blah == f2.a.blah F.a.wazoo = F f1.a.wazoo is f2.a.wazoo # try setting __dict__ illegally try: F.a.__dict__ = (1, 2, 3) except TypeError: pass else: print 'did not get expected TypeError' F.a.__dict__ = {'one': 111, 'two': 222, 'three': 333} print f1.a.two == 222 from UserDict import UserDict d = UserDict({'four': 444, 'five': 555}) F.a.__dict__ = d try: f2.a.two except AttributeError: pass else: print 'did not get expected AttributeError' print f2.a.four is f1.a.four is F.a.four
On Mon, 10 Apr 2000, Barry Warsaw wrote:
... Below is a very raw set of patches to add an attribute dictionary to funcs and methods. It's only been minimally tested, but if y'all like the idea,
+1 on concept, -1 on the patch :-)
... P.S. I promised to add a little note about setattr and getattr vs. setattro and getattro. There's very little documentation about the differences, and searching on python.org doesn't seem to turn up anything. The differences are simple. setattr/getattr take a char* argument naming the attribute to change, while setattro/getattro take a PyObject* (hence the trailing `o' -- for Object). This stuff should get documented in the C API, but at least now, it'll turn up in a SIG search. :)
And note that the getattro/setattro is preferred. It is easy to extract the char* from them; the other direction requires construction of an object.
... + static int + instancemethod_setattr(im, name, v) + register PyMethodObject *im; + char *name; + PyObject *v;
IMO, this should be instancemethod_setattro() and take a PyObject *name. In the function, you can extract the string for comparison.
... + { + int rtn;
This variable isn't used.
... static PyObject * instancemethod_getattr(im, name) register PyMethodObject *im; ! char *name;
IMO, this should remain a getattro function. (and fix the name) In your update, note how many GetAttrString calls there are. The plain GetAttr is typically faster.
... + rtn = PyMember_Get((char *)im, instancemethod_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyObject_GetAttrString(im->im_func, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name);
Why do you mask this second error with the AttributeError? Seems that you should just leave whatever is there (typically an AttributeError, but maybe not!).
... --- 144,167 ---- PyFunctionObject *op; char *name; { + PyObject* rtn; + if (name[0] != '_' && PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "function attributes not accessible in restricted mode"); return NULL; + } + if (strcmp(name, "__dict__") == 0) + return op->func_dict;
This is superfluous. The PyMember_Get will do this.
+ rtn = PyMember_Get((char *)op, func_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyDict_GetItemString(op->func_dict, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name);
Again, with the masking...
... + else if (strcmp(name, "func_dict") == 0) { + if (value == NULL || !PyDict_Check(value)) { + PyErr_SetString( + PyExc_TypeError, + "func_dict must be set to a dict object");
This raises an interesting thought. Why not just require the mapping protocol? Cheers, -g -- Greg Stein, http://www.lyra.org/
Below is a very raw set of patches to add an attribute dictionary to funcs and methods. It's only been minimally tested, but if y'all like the idea,
"GS" == Greg Stein <gstein@lyra.org> writes:
GS> +1 on concept, -1 on the patch :-) Well, that's good, because I /knew/ the patch was a quick hack (which is why I posted it to python-dev and not patches :). Since there's been generally positive feedback on the idea, I think I'll flesh it out a bit. GS> And note that the getattro/setattro is preferred. It is easy GS> to extract the char* from them; the other direction requires GS> construction of an object. Good point.
... + rtn = PyMember_Get((char *)im, instancemethod_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyObject_GetAttrString(im->im_func, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name);
GS> Why do you mask this second error with the AttributeError? GS> Seems that you should just leave whatever is there (typically GS> an AttributeError, but maybe not!). Good point here, but...
+ rtn = PyMember_Get((char *)op, func_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyDict_GetItemString(op->func_dict, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name);
GS> Again, with the masking... ...here I don't want the KeyError to leak through the getattr() call. If you do "print func.non_existent_attr" wouldn't you want an AttributeError instead of a KeyError? Maybe it should explicitly test for KeyError rather than masking any error coming back from PyDict_GetItemString()? Or better yet (based on your suggestion below), it should do a PyMapping_HasKey() test, raise an AttributeError if not, then just return PyMapping_GetItemString().
... + else if (strcmp(name, "func_dict") == 0) { + if (value == NULL || !PyDict_Check(value)) { + PyErr_SetString( + PyExc_TypeError, + "func_dict must be set to a dict object");
GS> This raises an interesting thought. Why not just require the GS> mapping protocol? Good point again. -Barry
On Mon, 10 Apr 2000 bwarsaw@python.org wrote:
...
... + rtn = PyMember_Get((char *)im, instancemethod_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyObject_GetAttrString(im->im_func, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name);
GS> Why do you mask this second error with the AttributeError? GS> Seems that you should just leave whatever is there (typically GS> an AttributeError, but maybe not!).
Good point here, but...
+ rtn = PyMember_Get((char *)op, func_memberlist, name); + if (rtn == NULL) { + PyErr_Clear(); + rtn = PyDict_GetItemString(op->func_dict, name); + if (rtn == NULL) + PyErr_SetString(PyExc_AttributeError, name);
GS> Again, with the masking...
...here I don't want the KeyError to leak through the getattr() call.
Ah! Subtle difference in the code there :-) I agree with you, on remapping the second one. I don't think the first needs to be remapped, however.
If you do "print func.non_existent_attr" wouldn't you want an AttributeError instead of a KeyError? Maybe it should explicitly test for KeyError rather than masking any error coming back from PyDict_GetItemString()? Or better yet (based on your suggestion below), it should do a PyMapping_HasKey() test, raise an AttributeError if not, then just return PyMapping_GetItemString().
Seems that you could just do the PyMapping_GetItemString() and remap the error *if* it occurs. Presumably, the exception is the infrequent case and can stand to be a bit slower. Cheers, -g -- Greg Stein, http://www.lyra.org/
On Mon, 10 Apr 2000 bwarsaw@python.org wrote:
... GS> And note that the getattro/setattro is preferred. It is easy GS> to extract the char* from them; the other direction requires GS> construction of an object.
Good point.
Oh. Also, I noticed that you removed a handy optimization from the getattr function. Testing a character for '_' *before* calling strcmp() will save a good chunk of time, especially considering how often this function is used. Basically, review whether a quick test can save a strmp() call (and can be easily integrated). Cheers, -g -- Greg Stein, http://www.lyra.org/
Barry Warsaw wrote:
A number of people have played FAST and loose with function and method docstrings, including John Aycock[1], Zope's ORB[2]. Docstrings are handy because they are the one attribute on funcs and methods that are easily writable. But as more people overload the semantics for docstrings, we'll get collisions. I've had a number of discussions with folks about adding attribute dictionaries to functions and methods so that you can essentially add any attribute. Namespaces are one honking great idea -- let's do more of those!
Barry, I wonder what for... Just because there's a Python entity implemented as a C structure in which we can easily include a dict + access functions? I don't see the purpose of attaching state (vars) to an algorithm (i.e. a function). What are the benefits compared to class instances? And these special assignment rules because of the real overlap with real instances... Grrr, all this is pretty dark, conceptually. Okay, I inderstood: modules become classes, functions become instances, module variables are class variables, and classes become ... 2-nd order instances of modules. The only missing piece of the puzzle is a legal way to instantiate modules for obtaining functions and classes dynamically, because using eval(), the `new' module or The Hook is perceived as very hackish and definitely not OO. Once the puzzle would be solved, we'll discover that there would be only one additional little step towards inheritance for modules. How weird! Sounds like we're going to metaclass again... -1 until P3K. This is no so cute as it is dangerous. It opens the way to mind abuse. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252
Vladimir Marangozov wrote:
I don't see the purpose of attaching state (vars) to an algorithm (i.e. a function). What are the benefits compared to class instances?
And these special assignment rules because of the real overlap with real instances... Grrr, all this is pretty dark, conceptually.
-1 until P3K.
I agree. </F>
Vladimir Marangozov wrote:
...
I don't see the purpose of attaching state (vars) to an algorithm (i.e. a function).
A function is also an object.
What are the benefits compared to class instances?
If I follow you, you are saying that whenever you need to associate information with a function, you should wrap up the function and object into a class. But the end result of this transformation could be a program in which every single function is a class. That would be incredibly annoying, especially with Python's scoping rules. In general, it may not even be possible. Consider the following cases: * I need to associate a Java-style type declaration with a method so that it can be recognized based on its type during Java method dispatch. How would you do that with instances? * I need to associate a "grammar rule" with a Python method so that the method is invoked when the parser recognizes a syntactic construct in the input data. * I need to associate an IDL declaration with a method so that a COM interface definition can be generated from the source file. * I need to associate an XPath "pattern string" with a Python method so that the method can be invoked when a tree walker discovers a particular pattern in an XML DOM. * I need to associate multiple forms of documentation with a method. They are optimized for different IDEs, environments or languages.
And these special assignment rules because of the real overlap with real instances... Grrr, all this is pretty dark, conceptually.
I don't understand what you are saying here.
Once the puzzle would be solved, we'll discover that there would be only one additional little step towards inheritance for modules. How weird! Sounds like we're going to metaclass again...
I don't see what any of this has to do with Barry's extremely simple idea. Functions *are objects* in Python. It's too late to change that. Objects can have properties. Barry is just allowing arbitrary properties to be associated with functions. I don't see where there is anything mysterious here. -- Paul Prescod - ISOGEN Consulting Engineer speaking for himself "I and my companions suffer from a disease of the heart that can only be cured with gold", Hernan Cortes
Paul Prescod wrote:
* I need to associate a Java-style type declaration with a method so that it can be recognized based on its type during Java method dispatch.
class foo: typemap = {} def myfunc(self): pass typemap[myfunc] = typeinfo
* I need to associate a "grammar rule" with a Python method so that the method is invoked when the parser recognizes a syntactic construct in the input data.
class foo: rules = [] def myfunc(self): pass rules.append(pattern, myfunc)
* I need to associate an IDL declaration with a method so that a COM interface definition can be generated from the source file.
class foo: idl = {} def myfunc(self): pass idl[myfunc] = "declaration"
* I need to associate an XPath "pattern string" with a Python method so that the method can be invoked when a tree walker discovers a particular pattern in an XML DOM.
class foo: xpath = [] def myfunc(self): pass xpath.append("pattern", myfunc) </F>
Fredrik Lundh wrote:
Paul Prescod wrote:
* I need to associate a Java-style type declaration with a method so that it can be recognized based on its type during Java method dispatch.
class foo: typemap = {} def myfunc(self): pass typemap[myfunc] = typeinfo
Yes, I know that nearly everything is possible to be emulated via classes. But what is so bad about an arbitrary function attribute? ciao - chris p.s.: Paul, did you know that you can use *anything* for __doc__? You could use a class instance instead which still serves as a __doc__ but has your attributes and more. Yes I know this is ugly :-)) -- Christian Tismer :^) <mailto:tismer@appliedbiometrics.com> Applied Biometrics GmbH : Have a break! Take a ride on Python's Kaunstr. 26 : *Starship* http://starship.python.net 14163 Berlin : PGP key -> http://wwwkeys.pgp.net PGP Fingerprint E182 71C7 1A9D 66E9 9D15 D3CC D4D7 93E2 1FAE F6DF where do you want to jump today? http://www.stackless.com
Functions and methods are first class objects, and they already have attributes, some of which are writable. Why should __doc__ be special? Just because it was the first such attribute to have syntactic support for easily defining? Think about my proposal this way: it actual removes a restriction. What I don't like about /F's approach is that if you were building a framework, you'd now have two conventions you'd have to describe: where to find the mapping, and what keys to use in that mapping. With attributes, you've already got the former: getattr(). Plus, let's say you're handed a method object `x', would you rather do: if x.im_class.typemap[x.im_func] == 'int': ... or if x.__type__ == 'int': ... And what about function objects (as opposed to unbound methods). Where do you stash the typemap? In the module, I supposed. And if you can be passed either type of object, do you now have to do this? if hasattr(x, 'im_class'): if hasattr(x.im_class, 'typemap'): if x.im_class.typemap[x.im_func] == 'int': ... elif hasattr(x, 'func_globals'): if x.func_globals.has_key('typemap'): if x.func_globals['typemap'][x] == 'int': ... instead of the polymorphic elegance of if x.__type__ == 'int': ... Finally, think of this proposal as an evolutionary step toward enabling all kinds of future frameworks. At some point, there may be some kind of optional static type system. There will likely be some syntactic support for easily specifying the contents of the __type__ attribute. With the addition of func/meth attrs now, we can start to play with prototypes of this system, define conventions and standards, and then later when there is compiler support, simplify the definitions, but not have to change code that uses them. -Barry
"BAW" == Barry A Warsaw <bwarsaw@cnri.reston.va.us> writes:
BAW> Functions and methods are first class objects, and they already BAW> have attributes, some of which are writable. Why should BAW> __doc__ be special? Just because it was the first such BAW> attribute to have syntactic support for easily defining? I don't have a principled argument about why doc strings should be special, but I think that they should be. I think it's weird that you can change __doc__ at runtime; I would prefer that it be constant. BAW> Think about my proposal this way: it actually removes a BAW> restriction. I think this is really the crux of the matter! The proposal removes a useful restriction. The alternatives /F suggested seem clearer to me that sticking new attributes on functions and methods. Three things I like about the approach: It affords an opportunity to be very clear about how the attributes are intended to be used. I suspect it would be easier to describe with a static type system. It prevents confusion and errors that might result from unprincipled use of function attributes. Jeremy
Jeremy Hylton wrote:
BAW> Think about my proposal this way: it actually removes a BAW> restriction.
I think this is really the crux of the matter! The proposal removes a useful restriction.
The alternatives /F suggested seem clearer to me that sticking new attributes on functions and methods. Three things I like about the approach: It affords an opportunity to be very clear about how the attributes are intended to be used. I suspect it would be easier to describe with a static type system.
Having to be explicit about the method <-> regex / rule would severely damage SPARK's elegance. It would make Tim's doctest useless.
It prevents confusion and errors that might result from unprincipled use of function attributes.
While I'm sure I will be properly shocked and horrified when you come up with an example, in my naivety, I can't imagine what it will look like ;-). - Gordon
"GMcM" == Gordon McMillan <gmcm@hypernet.com> writes: [please imagine that the c is raised]
BAW> Think about my proposal this way: it actually removes a BAW> restriction. [Jeremy Hylton wrote:]
I think this is really the crux of the matter! The proposal removes a useful restriction.
The alternatives /F suggested seem clearer to me that sticking new attributes on functions and methods. Three things I like about the approach: It affords an opportunity to be very clear about how the attributes are intended to be used. I suspect it would be easier to describe with a static type system.
GMcM> Having to be explicit about the method <-> regex / rule would GMcM> severely damage SPARK's elegance. It would make Tim's doctest GMcM> useless. Do either of these examples modify the __doc__ attribute? I am happy to think of both of them as elegant abuses of the doc string. (Not sure what semantics I mean for "elegant abuse" but not pejorative.) I'm not arguing that we should change the language to prevent them from using doc strings. Fred and I were just talking, and he observed that a variant of Python that included a syntactic mechanism to specify more than one attribute (effectively, a multiple doc string syntax) might be less objectionable than setting arbitrary attributes at runtime. Neither of us could imagine just what that syntax would be.
It prevents confusion and errors that might result from unprincipled use of function attributes.
GMcM> While I'm sure I will be properly shocked and horrified when GMcM> you come up with an example, in my naivety, I can't imagine GMcM> what it will look like ;-). It would look really, really bad ;-). I couldn't think of a good example, so I guess this is a FUD argument. A rough sketch, though, would be a program that assigned attribute X to all functions that were to be used in a certain way. If the assignment is a runtime operation, rather than a syntactic construct that defines a static attribute, it would be possible to accidentally assign attribute X to a function that was not intended to be used that way. This connection between a group of functions and a particular behavior would depend entirely on some runtime magic with settable attributes. Jeremy
"JH" == Jeremy Hylton <jeremy@cnri.reston.va.us> writes:
JH> Fred and I were just talking, and he observed that a variant JH> of Python that included a syntactic mechanism to specify more JH> than one attribute (effectively, a multiple doc string syntax) JH> might be less objectionable than setting arbitrary attributes JH> at runtime. Neither of us could imagine just what that syntax JH> would be. So it's the writability of the attributes that bothers you? Maybe we need WORM-attrs? :) -Barry
bwarsaw@cnri.reston.va.us wrote:
"JH" == Jeremy Hylton <jeremy@cnri.reston.va.us> writes:
JH> Fred and I were just talking, and he observed that a variant JH> of Python that included a syntactic mechanism to specify more JH> than one attribute (effectively, a multiple doc string syntax) JH> might be less objectionable than setting arbitrary attributes JH> at runtime. Neither of us could imagine just what that syntax JH> would be.
So it's the writability of the attributes that bothers you? Maybe we need WORM-attrs? :)
Why don't you just use WORM programming style. Write it once (into the CVS) and get many complaints :-) chris -- Christian Tismer :^) <mailto:tismer@appliedbiometrics.com> Applied Biometrics GmbH : Have a break! Take a ride on Python's Kaunstr. 26 : *Starship* http://starship.python.net 14163 Berlin : PGP key -> http://wwwkeys.pgp.net PGP Fingerprint E182 71C7 1A9D 66E9 9D15 D3CC D4D7 93E2 1FAE F6DF where do you want to jump today? http://www.stackless.com
On Wed, 12 Apr 2000, Jeremy Hylton wrote:
... It would look really, really bad ;-). I couldn't think of a good example, so I guess this is a FUD argument. A rough sketch, though, would be a program that assigned attribute X to all functions that were to be used in a certain way. If the assignment is a runtime operation, rather than a syntactic construct that defines a static attribute, it would be possible to accidentally assign attribute X to a function that was not intended to be used that way. This connection between a group of functions and a particular behavior would depend entirely on some runtime magic with settable attributes.
This is a FUD argument also. I could just as easily mis-label a function when using __doc__ strings, when using mappings in a class object, or using some runtime structures to record the attribute. Your "label" can be recorded in any number of ways. It can be made incorrect in all of them. There is nothing intrinsic to function attributes that makes them more prone to error. Being able to place them into function attributes means that you have a better *model* for how you record these values. Why place them into a separate mapping if your intent is to enhance the semantics of a function? If the semantics apply to a function, then bind it right there. Cheers, -g -- Greg Stein, http://www.lyra.org/
Greg Stein wrote: ...
Being able to place them into function attributes means that you have a better *model* for how you record these values. Why place them into a separate mapping if your intent is to enhance the semantics of a function? If the semantics apply to a function, then bind it right there.
BTW., is then there also a way for the function *itself* so look into its attributes? If it should be able to take special care about its attributes, it would be not nice if it had to know its own name for that? Some self-like surrogate? ciao - chris -- Christian Tismer :^) <mailto:tismer@appliedbiometrics.com> Applied Biometrics GmbH : Have a break! Take a ride on Python's Kaunstr. 26 : *Starship* http://starship.python.net 14163 Berlin : PGP key -> http://wwwkeys.pgp.net PGP Fingerprint E182 71C7 1A9D 66E9 9D15 D3CC D4D7 93E2 1FAE F6DF where do you want to jump today? http://www.stackless.com
On Wed, 12 Apr 2000, Christian Tismer wrote:
Greg Stein wrote: ...
Being able to place them into function attributes means that you have a better *model* for how you record these values. Why place them into a separate mapping if your intent is to enhance the semantics of a function? If the semantics apply to a function, then bind it right there.
BTW., is then there also a way for the function *itself* so look into its attributes? If it should be able to take special care about its attributes, it would be not nice if it had to know its own name for that? Some self-like surrogate?
Separate problem. Functions can't do that today with their own __doc__ attribute. Feel free to solve this issue, but it is distinct from the attributes-on-functions issue being discussed. Cheers, -g -- Greg Stein, http://www.lyra.org/
Gordon McMillan:
Jeremy Hylton wrote:
It prevents confusion and errors that might result from unprincipled use of function attributes.
While I'm sure I will be properly shocked and horrified when you come up with an example, in my naivety, I can't imagine what it will look like ;-).
I'm w/ Gordon & Barry on this one. I've wanted method and function attributes in the past and had to rely on building completely new classes w/ __call__ methods just to 'fake it'. There's a performance cost to having to do that, but most importantly there's a big increase in code complexity, readability, maintanability, yaddability, etc. I'm surprised that Jeremy sees it as such a problem area -- if I wanted to play around with static typing, having a version of Python which let me store method metadata cleanly would make me jump with joy. FWIW, I'm perfectly willing to live in a world where 'unprincipled use of method and function attributes' means that my code can't get optimized, just like I don't expect my code which modifies __class__ to get optimized (as long as someone defines what those principles are!). --david
Lisp systems for 40+ years traditionally supported user-muckable "property lists" on all symbols, which were basically arbitrary dicts w/ a clumsy syntax. No disaster ensued; to the contrary, it was often handy. So +0 from me on the add-attrs-to-funcs idea. The same idea applies to all objects, of course, but attrs-on-funcs has some bang for the buck (adding a dict to e.g. each int object would be a real new burden with little payback). -1 on any notion of restricting attr values to be immutable. [Gordon]
Having to be explicit about the method <-> regex / rule would severely damage SPARK's elegance.
That's why I'm only +0 instead of +1: SPARK won't switch to use the new method anyway, because the beauty of abusing docstrings is that it's syntactically *obvious*. There already exist any number of other ways to associate arbitrary info with arbitrary objects, and it's no mystery why SPARK and Zope avoided all of them in favor of docstring abuse.
It would make Tim's doctest useless.
This one not so: doctest is *not* meant to warp docstrings toward testing purposes; it's intended that docstrings remain wholly for human-friendly documentation. What doctest does is give you a way to guarantee that the elucidating examples good docstrings *should have anyway* work exactly as advertised (btw, doctest examples found dozens of places in my modules that needed to be fixed to recover from 1.6 alpha no longer sticking a trailing "L" on str(long) -- if you're not using doctest every day, you're an idiot <wink>). If I could add an attr to funcs, though, *then* I'd think about changing doctest to also run examples in any e.g. func.doctest attrs it could find, and that *new* mechanism would be warped toward testing purposes. Indeed, I think that would be an excellent use for the new facility. namespaces-are-one-honking-great-etc-ly y'rs - tim
Jeremy Hylton wrote:
BAW> Think about my proposal this way: it actually removes a BAW> restriction.
I think this is really the crux of the matter! The proposal removes a useful restriction.
Not sure... I wouldn't mind having the ability to add attributes to all Python objects at my own liking. Ok, maybe a bit far fetched, but the idea would certainly be useful in some cases, e.g. to add new methods to built-in types or to add encoding name information to strings...
The alternatives /F suggested seem clearer to me that sticking new attributes on functions and methods. Three things I like about the approach: It affords an opportunity to be very clear about how the attributes are intended to be used. I suspect it would be easier to describe with a static type system. It prevents confusion and errors that might result from unprincipled use of function attributes.
The nice side-effect of having these function/method instance dictionaries is that they follow class inheritance. Something which is hard to do right with Fredrik's approach. I suspect that in Py3K we'll only have one type of class system: everything inherits from one global base class -- seen in that light, method attributes are really nothing unusual, since all instances would have instance dictionaries anyway (well maybe only on demand, but that's another story). Anyway, more power to you Barry :-) -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/
BAW> Functions and methods are first class objects, and they already BAW> have attributes, some of which are writable. (Trying to read Fredrik's mind...) By extension, we should allow writable attributes to work for other objects. To pollute this discussion with an example from another one: i = 3.1416 i.__precision__ = 4 I haven't actually got anything against adding attributes to functions (or numbers, if it's appropriate). Just wondering out loud and playing a bit of a devil's advocate. Skip
On Wed, 12 Apr 2000, Skip Montanaro wrote:
To pollute this discussion with an example from another one:
i = 3.1416 i.__precision__ = 4
And voila! Numbers are no longer immutable. Using any numbers as keys in dicts? Moshe Zadka <mzadka@geocities.com>. http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com
On Wed, 12 Apr 2000, Fredrik Lundh wrote:
so? you can use methods as keys today, you know...
Actually, I didn't know. What hapens if you use a method as a key, and then change it's doc string? -- Moshe Zadka <mzadka@geocities.com>. http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com
"MZ" == Moshe Zadka <moshez@math.huji.ac.il> writes:
>> so? you can use methods as keys today, you know... MZ> Actually, I didn't know. What hapens if you use a method as a MZ> key, and then change it's doc string? Nothing. Python 1.5.2 (#7, Apr 16 1999, 18:24:22) [GCC 2.8.1] on sunos5 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
def foo(): ... 'a doc string' ... d = {} d[foo] = foo foo.__doc__ = 'norwegian blue' d[foo].__doc__ 'norwegian blue'
The hash of a function object is hash(func_code) ^ id(func_globals): Python 1.6a2 (#26, Apr 12 2000, 13:53:57) [GCC 2.8.1] on sunos5 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
def foo(): pass ... hash(foo) 557536160 hash(foo.func_code) 557215928 id(foo.func_globals) 860952 hash(foo.func_code) ^ id(foo.func_globals) 557536160
So in the words of Mr. Praline: The plumage don't enter into it. :) But you can still get quite evil: Python 1.6a2 (#26, Apr 12 2000, 13:53:57) [GCC 2.8.1] on sunos5 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
def foo(): pass ... def bar(): print 1 ... d = {} d[foo] = foo d[foo] <function foo at dee08> foo.func_code = bar.func_code d[foo] Traceback (most recent call last): File "<stdin>", line 1, in ? KeyError: <function foo at dee08>
Mwah, ha, ha! Gimme-lists-as-keys-and-who-really-/does/-need-tuples-after-all?-ly y'rs, -Barry
Moshe> On Wed, 12 Apr 2000, Skip Montanaro wrote: >> To pollute this discussion with an example from another one: >> >> i = 3.1416 >> i.__precision__ = 4 >> Moshe> And voila! Numbers are no longer immutable. Using any numbers as Moshe> keys in dicts? Yes, and I use functions on occasion as dict keys as well. >>> def foo(): pass ... >>> d = {foo: 1} >>> print d[foo] 1 I suspect adding methods to functions won't invalidate their use in that context, nor would adding attributes to numbers. At any rate, it was just an example. Skip
Skip Montanaro wrote:
BAW> Functions and methods are first class objects, and they already BAW> have attributes, some of which are writable.
(Trying to read Fredrik's mind...)
takes too long since it isn't countable infinite...
By extension, we should allow writable attributes to work for other objects. To pollute this discussion with an example from another one:
i = 3.1416 i.__precision__ = 4
I haven't actually got anything against adding attributes to functions (or numbers, if it's appropriate). Just wondering out loud and playing a bit of a devil's advocate.
please let me join your hexensabbat (de|en)lighted-ly -y'rs - rapunzel -- Christian Tismer :^) <mailto:tismer@appliedbiometrics.com> Applied Biometrics GmbH : Have a break! Take a ride on Python's Kaunstr. 26 : *Starship* http://starship.python.net 14163 Berlin : PGP key -> http://wwwkeys.pgp.net PGP Fingerprint E182 71C7 1A9D 66E9 9D15 D3CC D4D7 93E2 1FAE F6DF where do you want to jump today? http://www.stackless.com
On Wed, 12 Apr 2000, Gordon McMillan wrote:
Bounded, however. And therefore, um, dense <duck>...
I sorta imagined it more like the Cantor set. Nowhere dense, but perfect <wink> sorry-but-he-started-with-the-maths-ly y'rs, Z. -- Moshe Zadka <mzadka@geocities.com>. http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com
"SM" == Skip Montanaro <skip@mojam.com> writes:
BAW> Functions and methods are first class objects, and they BAW> already have attributes, some of which are writable. SM> (Trying to read Fredrik's mind...) SM> By extension, we should allow writable attributes to work for SM> other objects. To pollute this discussion with an example SM> from another one: | i = 3.1416 | i.__precision__ = 4 SM> I haven't actually got anything against adding attributes to SM> functions (or numbers, if it's appropriate). Just wondering SM> out loud and playing a bit of a devil's advocate. Python 1.6a2 (#26, Apr 12 2000, 13:53:57) [GCC 2.8.1] on sunos5 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
i = 3.1416 dir(i) []
Floats don't currently have attributes. -Barry
BAW> Functions and methods are first class objects, and they already BAW> have attributes, some of which are writable. SM> I haven't actually got anything against adding attributes to SM> functions (or numbers, if it's appropriate). Just wondering out SM> loud and playing a bit of a devil's advocate. BAW> Python 1.6a2 (#26, Apr 12 2000, 13:53:57) [GCC 2.8.1] on sunos5 BAW> Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>>> i = 3.1416 >>>> dir(i) BAW> [] BAW> Floats don't currently have attributes. True enough, but why can't they? I see no reason that your writable function attributes proposal requires that functions already have attributes. Modifying my example, how about: >>> l = [1,2,3] >>> l.__type__ = "int" Like functions, lists do have (readonly) attributes. Why not allow them to have writable attributes as well? Awhile ago, Paul Prescod proposed something I think he called a super tuple, which allowed you to address tuple elements using attribute names: >>> t = ("x": 1, "y": 2, "z": 3) >>> print t.x 1 >>> print t[1] 2 (or something like that). I'm sure Paul or others will chime in if they think it's relevant. Your observation was that functions have a __doc__ attribute that is being abused in multiple, conflicting ways because it's the only function attribute people have to play with. I have absolutely no quibble with that. See: http://www.python.org/pipermail/doc-sig/1999-December/001671.html (Note that it apparently fell on completely deaf ears... ;-) I like your proposal. I was just wondering out loud if it should be more general. Skip
"SM" == Skip Montanaro <skip@mojam.com> writes:
BAW> Floats don't currently have attributes. SM> True enough, but why can't they? Skip, didn't you realize I was setting you up to ask that question? :) I don't necessarily think other objects shouldn't have such attributes, but I thought it might be easier to shove this one tiny little pill down peoples' throats first. Once they realize it tastes good, /they'll/ want more :) SM> Awhile ago, Paul Prescod proposed something I think he called SM> a super tuple, which allowed you to address tuple elements SM> using attribute names: >> t = ("x": 1, "y": 2, "z": 3) print t.x | 1 | >>> print t[1] | 2 SM> (or something like that). I'm sure Paul or others will chime SM> in if they think it's relevant. Might be. I thought that was a cool idea too at the time. SM> Your observation was that functions have a __doc__ attribute SM> that is being abused in multiple, conflicting ways because SM> it's the only function attribute people have to play with. I SM> have absolutely no quibble with that. See: SM> SM> http://www.python.org/pipermail/doc-sig/1999-December/001671.html SM> (Note that it apparently fell on completely deaf ears... ;-) I SM> like your proposal. I was just wondering out loud if it SM> should be more general. Perhaps so. -Barry
On Wed, 12 Apr 2000, Skip Montanaro wrote:
... BAW> Floats don't currently have attributes.
True enough, but why can't they? I see no reason that your writable function attributes proposal requires that functions already have attributes. Modifying my example, how about:
>>> l = [1,2,3] >>> l.__type__ = "int"
Like functions, lists do have (readonly) attributes. Why not allow them to have writable attributes as well?
Lists, floats, etc are *data*. There is plenty of opportunity for creating data structures that contain whatever you want, organized in any fashion. Functions are (typically) not data. Applying these attributes is a way to define program semantics, not record data. There are two entirely separate worlds here. Adding attributes makes great sense, as a way to enhance the definition of your program's semantics and operation. Cheers, -g -- Greg Stein, http://www.lyra.org/
me> >>> l = [1,2,3] me> >>> l.__type__ = "int" Greg> Lists, floats, etc are *data*. There is plenty of opportunity for Greg> creating data structures that contain whatever you want, organized Greg> in any fashion. Yeah, but there's no reason you wouldn't want to reason about them. They are, after all, first-class objects. If you consider these other attributes as meta-data, allowing data attributes to hang off lists, tuples, ints or regex objects makes perfect sense to me. I believe someone else during this thread suggested that one use of function attributes might be to record the function's return type. My example above is not really any different. Simpleminded, yes. Part of the value of l, no. Skip
On Wed, 12 Apr 2000, Skip Montanaro wrote:
BAW> Functions and methods are first class objects, and they already BAW> have attributes, some of which are writable.
(Trying to read Fredrik's mind...)
By extension, we should allow writable attributes to work for other objects. To pollute this discussion with an example from another one:
i = 3.1416 i.__precision__ = 4
I haven't actually got anything against adding attributes to functions (or numbers, if it's appropriate). Just wondering out loud and playing a bit of a devil's advocate.
Numbers have no attributes right now. Functions have mutable attributes (__doc__). Barry is allowing them to be annotated (without crushing the values into __doc__ in some nasty way). Paul gave some great examples. IMO, the Zope "visibility by use of __doc__" is the worst kind of hack :-) "Let me be a good person and doc all my functions. Oh, crap! Somebody hacked my system!" And the COM thing was great. Here is what we do today: class MyCOMServer: _public_methods_ = ['Hello'] def private_method(self, args): ... def Hello(self, args) ... The _public_methods_ thing is hacky. I'd rather see a "Hello.public = 1" in there. Cheers, -g -- Greg Stein, http://www.lyra.org/
Barry A. Warsaw wrote:
Finally, think of this proposal as an evolutionary step toward enabling all kinds of future frameworks. /.../ With the addition of func/meth attrs now, we can start to play with prototypes of this system, define conventions and standards /.../
does this mean that this feature will be labelled as "experimental" (and hopefully even "interpreter specific"). if so, +0. </F>
"FL" == Fredrik Lundh <effbot@telia.com> writes:
FL> does this mean that this feature will be labelled as FL> "experimental" (and hopefully even "interpreter specific"). Do you mean "don't add it to JPython whenever I actually get around to making it compatible with CPython 1.6"? -Barry
Vladimir Marangozov writes:
Barry, I wonder what for...
In the two quoted examples, docstrings are used to store additional info about a function. SPARK uses them to contain grammar rules and the regular expressions for matching tokens. The object publisher in Zope uses the presence of a docstring to indicate whether a function or method is publicly accessible. As a third example, the optional type info being thrashed over in the Types-SIG would be another annotation for a function (though doing def f(): ... f.type = 'void' would be really clunky.
Once the puzzle would be solved, we'll discover that there would be only one additional little step towards inheritance for modules. How weird! Sounds like we're going to metaclass again...
No, that isn't why Barry is experimenting with this -- instead, it's simply because annotating functions seems useful, but everyone uses the docstring because it's the only option. --amk
participants (18)
-
Andrew Kuchling
-
Barry A. Warsaw
-
bwarsaw@cnri.reston.va.us
-
bwarsaw@python.org
-
Christian Tismer
-
David Ascher
-
Fredrik Lundh
-
Fredrik Lundh
-
Gordon McMillan
-
Greg Stein
-
Guido van Rossum
-
Jeremy Hylton
-
M.-A. Lemburg
-
Moshe Zadka
-
Paul Prescod
-
Skip Montanaro
-
Tim Peters
-
Vladimir.Marangozov@inrialpes.fr