[ZODB-Dev] Persistent-derived class instances always callable

Tim Peters tim at zope.com
Sat Oct 18 02:03:01 EDT 2003


[Shane Hathaway]
> Zope uses callable() heavily.  No, I take it back--it used to use
> callable(), until we discovered it does not work at all with
> ExtensionClasses.  Zope now uses its own implementation of callable().

In fact, I see there are several of them <wink>.

> Consider that there are two kinds of weakref proxies: callable and
> non-callable.  AFAIK the only reason for this is to work around the
> expectations of callable().

I'm sure it's much more for efficiency.  The only cost to having the two
types is that there are two type objects -- they share almost all of their
implementations (one has a NULL tp_call slot, the other doesn't, and that's
it apart from the name difference).  Type objects are cheap and easy.  If
they shared a type object, then every time a call was made the
implementation of the proxy tp_call would first have to sniff at the proxied
object to determine whether it was callable, and then branch based on that,
raising a particular exception in one case, going thru the call dance in the
other case.  That would actually require more *code* than the method Fred
chose, and would run slower.  Instead he decided to follow what's obvious in
Python's design:  a thing is callable if and only if it has a non-NULL
tp_call slot (excepting the old wart for instances of old-style classes,
which resort to sniffing for "__call__").  That's vanilla OO design, and has
the expected happy outcome of eliminating all need for runtime type-sniffing
when an attempt to call via a proxy object (of either flavor) occurs.

> Does this mean everyone who writes proxies (such as the acquisition
> wrappers in ExtensionClass and Zope 3's context wrappers) needs to
> follow this same pattern?

If they want to minimize code, and avoid needless problems and runtime sloth
due to fighting Python's design, yes, they should.  If ExtensionClass hadn't
turned out to play by its own and different rules here, I doubt you'd be
typing about this at all now; I don't know of any other extension that
causes a problem here, and doubt that ExtensionClass did so deliberately.

> If Python someday adds builtins like iterable() and hashable() in
> addition to callable(), and they only look at slots, does that mean
> there will be *eight* weakref proxy types?

More, if it adds N such things, there may be at least 2**(N+1) such types.
There's no reason to expect Python will ever add such things, though (it's
been 10 years since the first-- and last --was introduced <0.9 wink>).

>> If it is needed, and you don't want to fight a losing battle with the
>> language design, then it's going to be a user-land convention. For
>> example, create an ICallable interface, and use the interface
>> machinery to declare with objects think they're callable, then check
>> an object to see whether it implements ICallable.

> I agree.  My position is that callable() ought to be reliable or it
> ought to be deprecated.

__builtin__.callable exposes Python's C API PyCallable_Check() function, and
as far as Python is concerned it's wholly reliable, but only to the extent
the documentation promises:

    callable(object)
    Return true if the object argument appears callable, false if not.
    If this returns true, it is still possible that a call fails, but
    if it is false, calling object will never succeed.

ExtensionClass's oddity here supports it to that extent too, and that's all
Python needs from it.  It serves a legitimate purpose in Python; if Zope
needs a different meaning, fine, but then it's Zope's problem to arrange for
a stronger meaning (would Zope even have "a problem" here if ExtensionClass
hadn't created one?).

> Zope 2 wouldn't be hurt by deprecating it, and ideally Zope 3 won't
> even need it.  But right now it seems like Python can't decide whether
> callable() is good or not,

The Python implementation uses __builtin__.callable and PyCallable_Check
several dozen times.  It works fine for what Python wants from it, and I've
never heard Guido suggest to deprecate it.

> and it's leading to workarounds just to satisfy the needs of someone
> neither of us knows.

I expect this is unique to Zope (as is ExtensionClass, and expect that this
is more than coincidence <wink>).




More information about the ZODB-Dev mailing list