[Python-Dev] Customizing the binding of attributes
Guido van Rossum
guido@python.org
Fri, 24 Aug 2001 06:03:34 -0400
> From: "Guido van Rossum" <guido@python.org>
> > I'm not sure what you are asking about, but let me give an example.
> > You can write an auxiliary class that "describes" an instance
> > attribute. Instances of this "descriptor" class are stored in a class
> > dict. The descriptor class implements a method __get__ which is
> > called in two situations:
> >
> > (a) when a class attribute is retrieved, <attr>.__get__(None, <class>)
> > is called; this can return an unbound method
> >
> > (b) when an instance attribute is retrieved, <attr>.__get__(<inst>, <class)
> > is called; this can return a bound method
> >
> > Does this help?
From: "Thomas Heller" <thomas.heller@ion-tof.com>
> Yes, thanks. Exactly what I meant. You only forgot to mention that
> the descriptor class must derive from object: is this intended?
Yes, almost all new features require you to switch to new-style
classes; the classic class implementation is left unchanged (as much
as possible) for compatibility. In particular, classic classes can't
define __get__ to the effect above.
These descriptors semi-work as class attributes of classic classes,
but the corresponding __set__ feature does not, because classic
classes *always* store in __dict__ upon assignment; new-style classes
first look for a descriptor implementing __set__ (really the C
dispatch function tp_descr_set) and use that to override the default
assignment.
> I needed this to write
>
> class X:
> method = myinstancemethod(func)
>
> instead of
>
> class X:
> pass
> X.method = new.instancemethod(func, None, X)
>
> where myinstancemethod is the descriptor class, and func
> is any callable object (maybe a function implemented in C).
>
> Two additional comments:
>
> - Shouldn't (my)instancemethod be a builtin? Similar to
> staticmethod and classmethod?
Yes. I just checked this in. The new name is 'getset' unless you
have a better idea.
> - The following seems to be a bug (remember, I'm on Windows):
>
> C:\>c:\python22\python.exe
> Python 2.2a2 (#22, Aug 22 2001, 01:24:03) [MSC 32 bit (Intel)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
> >>> class myinstancemethod(object):
> ... def __init__(self, func):
> ... self.func = func
> ... def __get__(self, inst, klass=None):
> ... import new
> ... return new.instancemethod(self.func, inst, klass)
> ...
> >>> class X:
> ... meth = myinstancemethod(lambda *x: x)
> ...
> >>> X().meth
> <bound method X.<lambda> of <__main__.X instance at 007C7F04>>
> >>> X().meth()
> (<__main__.X instance at 007E80E4>,)
> >>> X.meth
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> SystemError: NULL object passed to Py_BuildValue
Yup. Thanks! Try this patch:
*** typeobject.c 2001/08/22 19:24:42 2.43
--- typeobject.c 2001/08/24 10:05:25
***************
*** 2806,2811 ****
--- 2806,2815 ----
Py_INCREF(self);
return self;
}
+ if (obj == NULL)
+ obj = Py_None;
+ if (type == NULL)
+ type = Py_None;
return PyObject_CallFunction(get, "OOO", self, obj, type);
}
--Guido van Rossum (home page: http://www.python.org/~guido/)