[Python-Dev] Getting rid of unbound methods: patch available

M.-A. Lemburg mal at egenix.com
Wed Jan 19 12:27:29 CET 2005


Guido van Rossum wrote:
> [me]
> 
>>>I'm not sure I understand how basemethod is supposed to work; I can't
>>>find docs for it using Google (only three hits for the query mxTools
>>>basemethod). How does it depend on im_class?
> 
> 
> [Marc-Andre]
> 
>>It uses im_class to find the class defining the (unbound) method:
>>
>>def basemethod(object,method=None):
>>
>>     """ Return the unbound method that is defined *after* method in the
>>         inheritance order of object with the same name as method
>>         (usually called base method or overridden method).
>>
>>         object can be an instance, class or bound method. method, if
>>         given, may be a bound or unbound method. If it is not given,
>>         object must be bound method.
>>
>>         Note: Unbound methods must be called with an instance as first
>>         argument.
>>
>>         The function uses a cache to speed up processing. Changes done
>>         to the class structure after the first hit will not be noticed
>>         by the function.
>>
>>     """
>>     ...
>>
>>This is how it is used in mixin classes to call the base
>>method of the overridden method in the inheritance tree (of
>>old-style classes):
>>
>>class RequestListboxMixin:
>>
>>     def __init__(self,name,viewname,viewdb,context=None,use_clipboard=0,
>>                  size=None,width=None,monospaced=1,events=None):
>>
>>         # Call base method
>>         mx.Tools.basemethod(self, RequestListboxMixin.__init__)\
>>                            (self,name,size,width,monospaced,None,events)
>>
>>         ...
>>
>>Without .im_class for the unbound method, basemethod would
>>seize to work since it uses this attribute to figure out
>>the class object defining the overriding method.
> 
> 
> Well, you could always do what Timothy Delaney's autosuper recipe
> does: crawl the class structure starting from object.__class__ until
> you find the requested method. Since you're using a cache the extra
> cost should be minimal.

That won't work, since basemethod() is intended for standard
classes (not new-style ones).

> I realize that this requires you to issue a new release of mxTools to
> support this, but you probably want to do one anyway to support other
> 2.5 features.

A new release wouldn't be much trouble, but I don't see any
way to fix the basemethod() implementation without also requiring
a change to the function arguments.

Current usage is basemethod(instance, unbound_method). In order
for basemethod to still be able to find the right class and
method name, I'd have to change that to basemethod(instance,
unbound_method_or_function, class_defining_method).

This would require all users of mx.Tools.basemethod() to
update their code base. Users will probably not understand
why this change is necessary, since they'd have to write
the class twice:

mx.Tools.basemethod(self,
                     RequestListboxMixin.__init__,
                     RequestListboxMixin)\
                     (self,name,size,width,monospaced,None,events)

Dropping the unbound method basically loses expressiveness:
without extra help from function attributes or other descriptors,
it would no longer be possible to whether a function is to be
used as method or as function. The defining namespace of the method
would also not be available anymore.

>>Hmm, I have a hard time seeing how you can get rid
>>off unbound methods while keeping bound methods - since
>>both are the same type :-)
> 
> Easy. There is a lot of code in the instance method type specifically
> to support the case where im_self is NULL. All that code can be
> deleted (once built-in exceptions stop using it).

So this is not about removing a type, but about removing
extra code. You'd still keep bound methods as separate
type.

>>I'm using PyMethod_Check() in mxProxy to automatically
>>wrap methods of proxied object in order to prevent references
>>to the object class or the object itself to slip by the
>>proxy. Changing the type to function object and placing
>>the class information into a function attribute would break
>>this approach. Apart from that the type change (by itself)
>>would not affect the eGenix code base.
> 
> 
> Isn't mxProxy a weak referencing scheme? Is it still useful given
> Python's own support for weak references?

Sure. First of all, mxProxy is more than just a weak referencing
scheme (in fact, that was only an add-on feature).

mxProxy allows you to wrap any Python object in way that hides
the object from the rest of the Python interpreter, putting
access to the object under fine-grained and strict control.
This is the main application space for mxProxy.

The weak reference feature was added later on, to work around
problems with circular references. Unlike the Python weak
referencing scheme, mxProxy allows creating weak references
to all Python objects (not just the ones that support the
Python weak reference protocol).

>>I would expect code in the following areas to make use
>>of the type check:
>>* language interface code (e.g. Java, .NET bridges)
> 
> Java doesn't have the concept of unbound methods, so I doubt it's
> useful there. Remember that as far as how you call it, the unbound
> method has no advantages over the function!

True, but you know that its a method and not just a function.
That can make a difference in how you implement the call.

>>* security code that tries to implement object access control
> 
> 
> Security code should handle plain functions just as well as (un)bound
> methods anyway.

It is very important for security code to know which attributes
are available on an object, e.g. an unbound method includes
the class object, which again has a reference to the module,
the builtins, etc.

Functions currently don't have this problem (but will once you add the
im_class attribute ;-).

>>* RPC applications that use introspection to generate
>>   interface definitions (e.g. WSDL service definitions)
> 
> 
> Why would those care about unbound methods?

I was thinking of iterating over the list of methods in
a class:

To find out which of the entries in the class
dict are methods, a tool would have to check whether
myClass.myMethod maps to an unbound method (e.g.
non-function callables are currently not wrapped as
unbound methods).

Example:

 >>> class C:
...     def test(self):
...             print 'hello'
...     test1 = dict
...
 >>> C.test1
<type 'dict'>
 >>> C.test
<unbound method C.test>

>>* debugging tools (e.g. IDEs)
> 
> Hopefuly those will use the filename + line number information in the
> function object. Remember, by the time the function is called, the
> (un)bound method object is unavailable.

I was thinking more in terms of being able to tell whether
a function is a method or not. IDEs might want to help
the user by placing a "(self," right after she types the
name of an unbound method.

>>>>If you want to make methods look more like functions,
>>>>the method object should become a subclass of the function
>>>>object (function + added im_* attributes).
>>>
>>>Can't do that, since the (un)bound method object supports binding
>>>other callables besides functions.
>>
>>Is this feature used anywhere ?
> 
> Yes, by the built-in exception code. (It surprised me too; I think in
> modern days it would have been done using a custom descriptor.)
> 
> BTW, decorators and other descriptors are one reason why approaches
> that insist on im_class being there will have a diminishing value in
> the future.

True, as long as you put the information from im_class somewhere
else (where it's easily accessible). However, I wouldn't want
to start writing

@method
def funcname(self, arg0, arg1):
     return 42

just to tell Python that this particular function will only
be used as method ;-)

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Jan 10 2005)
 >>> Python/Zope Consulting and Support ...        http://www.egenix.com/
 >>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
 >>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
________________________________________________________________________

::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::


More information about the Python-Dev mailing list