Having unbound methods refer to the classes their defined on
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.) 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? Ram.
On 6/1/2010 1:36 PM, cool-RR wrote:
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.
Actually, I believe it referred to the class through which the function was accessed. The object in the class __dict__ was still the function. In both 2.x and 3.x, a function can be an attribute of more than one class and might not have been defined 'on' any of them. Right or wrong, I believe it was thought that adding the wrapper was more of a nuisance than a benefit. I suppose you could propose that when a function is directly accessed as a class (as opposed to via an instance, when wrapping as a bound method is still done), an __access_class__ attribute could be added, but I do not know if that would even help you. Perhaps a custom metaclass could be written to do this now (I definitely do not know this for sure). Terry Jan Reedy
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
On Wed, Jun 2, 2010 at 8:36 AM, Gmail <arnodel@googlemail.com> wrote:
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
Thanks for the corrections and the metaclass, Arnaud. (And thanks to you too, Terry.) I might use it in my project.
so what you are asking for is different from what Python 2.X provided.
Yes, I have been imprecise. So I'll correct my idea: I want Python 3.x to tell me the class from which the unbound method was accessed. (It can be done either on creation or or access, whatever seems better to you.) So I propose this as a modification of Python. Ram.
participants (3)
-
cool-RR
-
Gmail
-
Terry Reedy