__getattr__ and __setattr__ troubles

Michael Hudson mwh21 at cam.ac.uk
Tue Jun 6 16:11:28 EDT 2000


=?ISO-8859-1?Q?Fran=E7ois_Pinard?= <pinard at iro.umontreal.ca> writes:

> "Adam Ruth" <aruth at intercation.com> writes:
> 
> > The __str__ and __coerce__, etc, will all be sent to __getattr__ because
> > they are *not* defined in the class.  If they were, then __getattr__
> > would never be called.
> 
> But would not this get fairly tedious?  For example:
> 
[snip]
> which is convenient enough for me.  While a simple:
                                              ^^^^^^
Overriding __getattr__ is not a simple business; it's probably unwise
to pretend it is.

Have you caused Python to crap out by infinite looping with
__getattr__ yet?

> ---------------------------------------------------------------------->
> class See:
> 
>     def __getattr__(self, key):
>         print '**', key
>         return None
> 
> print See()
> ----------------------------------------------------------------------<
> 
> will yield:
> 
> ---------------------------------------------------------------------->
> pinard at titan:~ $ python see.py
>  ** __str__
> Traceback (innermost last):
>   File "see.py", line 7, in ?
>     print See()
> TypeError: call of non-function (type None)
> ----------------------------------------------------------------------<
> 
> * By the way, and a bit unrelated, why the space before the two asterisks?

Probably to do with softspace.  Not sure.

> * The diagnostic would be rather cryptic, if the program was not so short.
>   Usability studies could be driven to show that the diagnostic should rather
>   be changed to something more informative :-).

Your wish is my command:

Index: classobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v
retrieving revision 2.86
diff -u -r2.86 classobject.c
--- classobject.c	2000/05/03 23:44:34	2.86
+++ classobject.c	2000/06/06 20:06:24
@@ -766,6 +766,10 @@
 		return PyString_FromString(buf);
 	}
 	res = PyEval_CallObject(func, (PyObject *)NULL);
+	if (res == NULL && !PyCallable_Check(func)) {
+		PyErr_SetString(PyExc_TypeError,
+	    "lookup for '__repr__' returned an uncallable object");
+	}
 	Py_DECREF(func);
 	return res;
 }
Index: object.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v
retrieving revision 2.70
diff -u -r2.70 object.c
--- object.c	2000/05/03 23:44:35	2.70
+++ object.c	2000/06/06 20:06:24
@@ -290,6 +290,10 @@
 			return PyObject_Repr(v);
 		}
 		res = PyEval_CallObject(func, (PyObject *)NULL);
+		if (res == NULL && !PyCallable_Check(func)) {
+			PyErr_SetString(PyExc_TypeError,
+		    "lookup for '__str__' returned an uncallable object");
+		}
 		Py_DECREF(func);
 	}
 	if (res == NULL)

Not sure it's a sufficiently common error to justify this though.
I'll send it to patches at python.org and see what they think of it.

> * May I least get the default string representation, which was satisfying?
> 
> * So, as soon as I use `__getattr__', I suddenly get a lot of other things to
>   define as well?  This would make `__getattr__' less attractive.

This is a good thing, as I tried to point out above.  It does horrible
things to performance too.  Overriding __getattr__ is good for "oo,
ain't that cool" value, but it is probably best to try to avoid it -
if you need it, fine, but consider alternatives first.

getting-worryingly-familiar-with-Python-internals-ly y'rs
Michael

-- 
  incidentally, asking why things are "left out of the language" is
  a good sign that the asker is fairly clueless.
                                        -- Erik Naggum, comp.lang.lisp



More information about the Python-list mailing list