On 1 Jun 2010, at 18:36, cool-RR wrote:
Hello,
I would like to raise an issue here that I've been discussing at python-porting.
(And I'd like to preface by saying that I'm not intimately familiar with Python's innards, so if I make any mistakes please correct me.)
In Python 2.x there was an "unbound method" type. An unbound method would have an attribute `.im_class` that would refer to the class on which the method was defined. This allowed users to use the `copy_reg` module to pickle unbound methods by name. (In a similar way to how functions and classes are pickled by default.)
Not exactly (python 2.6):
class Foo(object): ... def f(self): pass ... Foo.f <unbound method Foo.f> Foo.f.im_class <class '__main__.Foo'> class Bar(Foo): pass ... bar.f <unbound method Bar.f> Bar.f.im_class <class '__main__.Bar'>
In Python 3.x unbound methods are plain functions. There is no way of knowing on which class they are defined, so therefore it's impossible to pickle them. It is even impossible to tell `copyreg` to use a custom reducer: http://stackoverflow.com/questions/2932742/python-using-copyreg-to-define-re...
(To the people who wonder why would anyone want to pickle unbound methods: I know that it sounds like a weird thing to do. Keep in mind that sometimes your objects need to get pickled. For example if you're using the multiprocessing module, and you pass into it an object that somehow refers to an unbound method, then that method has to be picklable.)
The idea is: Let's give unbound methods an attribute that will refer to the class on which they were defined.
What do you think?
Unbound methods in Python 2.X were objects that were created on class attribute access, not when the class was created, so what you are asking for is different from what Python 2.X provided. Here is a very simplified way to mimic 2.X in 3.X via metaclasses (Python 3.2):
class FooType(type): ... def __getattribute__(self, attrname): ... attr = super().__dict__[attrname] ... if isinstance(attr, type(lambda:0)): ... return ("unbound method", self, attr) ... else: ... return attr ... class Foo(metaclass=FooType): ... def f(self):pass ... Foo.f ('unbound method', <class '__main__.Foo'>, <function f at 0x445fa8>) Foo().f()
What you want maybe instead is a metaclass that overrides type.__new__ or type.__init__ so that each function in the attributes of the class is wrapped in some kind of wrapper like this: class DefinedIn: def __init__(self, f, classdef): self.classdef = classdef self.f = f def __call__(self, *args, **kwargs): return self.f(*args, **kwargs) -- Arnaud