[Python-Dev] PEP 253: Subtyping Built-in Types

Guido van Rossum guido@digicool.com
Sun, 22 Jul 2001 12:42:49 -0400

> Hmm, I don't like these class methods, but it would probably
> help with the problem...
> from mx.DateTime import DateTime
> dt1 = DateTime(2001,1,16)
> dt2 = DateTime.From("16. Januar 2001")
> Still looks silly to me... (I don't like these class methods).

Maybe it's time you started to like them. :-)

> > I've been thinking about this.  I don't think that's quite the right
> > protocol; I don't want to complicate the DECREF macro any more.  I
> > think that tp_dealloc must call tp_del and then decide whether to
> > proceed depending on the refcount.
> Have you tried to move the decref action into a separate function
> (which is only called in case the refcount reaches 0) ? I think
> that this could in fact enhance the overall performance since 
> the compiler can then decide whether or not to inline the relevant
> code.
> I wonder what the impact would be...

My gut tells me that the compiler will usually *not* inline it, and
then it will slow deallocation down by one extra function call.  And
if the compiler *does* inline it, it's code bloat.  So either way you
lose, my gut tells me.  (The dealloc functions for most common types
are very fast and I would hate to see them slow down.)

> Good, so overriding the tp_alloc/free slots is generally not
> a wise thing to do, I guess.

If the base type has a custom free list (like the int type does), you
*have* to override it if the instances of the subtype are larger than
the base type.  Currently int doesn't allow subtyping yet because I
haven't refactored its code in this area yet.

> > > - Could the generic APIs perhaps fall back to tp_getattr to make
> > >   the transition from classic types to base types a little easier ?
> > 
> > I'd rather not: that would prevent discovery of attributes supported
> > by the classic tp_getattr.  The beauty of the new scheme is that *all*
> > attributes (methods and data) are listed in the type's __dict__.
> Uhm, I think you misunderstood me: tp_getattr is not used anymore
> once the Python interpreter finds a tp_getattro slot 
> implementation, so there's nothing to prevent ;-):
> PyObject_GetAttr() does not use tp_getattr if tp_getattro is 
> defined, while PyObject_GetAttrString() prefers tp_getattr over
> tp_getattro -- something is not symmertic here !
> As a result, dir() finds the __members__ attribute which lists
> the attributes (it uses PyObject_GetAttrString(), but 
> instance.attribute does not work because it uses PyObject_GetAttr().

The simplified rule is that a type should only provide *either*
tp_getattr *or* tp_getattro, and likewise for set.  The complete rule
is that if you insist on having both tp_getattr and tp_getattro, they
should implement the same semantics -- tp_getattr should be faster
when PyObject_GetAttrString() is called, and tp_getattro should be
faster when PyObject_GetAttr() is called.

Apparently you left your tp_getattr implementation in place but added
PyObject_GenericGetAttr to the tp_getattro slot -- this simply doesn't
follow the rules.

--Guido van Rossum (home page: http://www.python.org/~guido/)