[Zope-Coders] new.instancemethod behavior under py22 vs. py21

Guido van Rossum guido@python.org
Wed, 04 Jun 2003 06:58:49 -0400


> Here's a bit of code that acts differently under Python 2.2 vs. Python
> 2.1:
> 
> from ExtensionClass import Base
> from Acquisition import ImplicitAcquisitionWrapper
> import new
> 
> class anextensionclass(Base):
>     pass
> 
> def afunction(self):
>     return 1
> 
> a = anextensionclass()
> b = anextensionclass()
> c = ImplicitAcquisitionWrapper(a, b)
> 
> print new.instancemethod(afunction, c, c.__class__)
> 
> Under Python 2.1.3, this code barfs with:
> 
> Traceback (most recent call last):
>   File "rebindtest.py", line 15, in ?
>     print new.instancemethod(afunction, c, c.__class__)
> TypeError: instancemethod() argument 3 must be class, not ExtensionClass
> 
> While under Python 2.2.2, it prints:
> 
> <bound method anextensionclass.afunction of <anextensionclass instance
> at 8161678>>
> 
> I suspect the difference has something to do with type/class unification
> or perhaps some special casing put into Python 2.2 wrt ExtensionClass
> objects.

The difference is that in 2.1, new.instancemethod is a factory
function that does more strict typechecking than it needs to.  In 2.2,
new.instancemethod is the corresponding type itself, and its
constructor does only the minimum needed type checking (it checks that
the first argument is callable, and that's it).  In 2.1, new is a C
module; in 2.2, new is a Python module containing about 5 lines of
code. :-)

> In any case, given that this doesn't work under Python 2.1, can anyone
> shed some light on dynamically rebinding functions to extensionclass
> instances as methods under Python 2.1?

Assuming you really don't want the function to become a permanent
method of the class, you can do the following for regular classes:

  anextensionclass._func = afunction
  bound_method = anextensionclass._func
  del anextensionclass._func

I don't know if that works for ExtensionClasses but if it does, it may
be simpler than the solution you describe in your own followup.  Or
not (the temporary assignment is a gross hack of course).

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