10

Dear python 3 experts,

with python2, one could do the following (I know this is a bit hairy, but that's not the point here :p):

class A(object):
  def method(self, other):
    print self, other

class B(object): pass

B.method = types.MethodType(A().method, None, B)
B.method() # print both A and B instances

with python3, there is no more unbound methods, only functions. If I want the same behaviour, it sounds like I've to introduce a custom descriptor such as:

class UnboundMethod:
    """unbound method wrapper necessary for python3 where we can't turn
    arbitrary object into a method (no more unbound method and only function
    are turned automatically to method when accessed through an instance)
    """
    def __init__(self, callable):
        self.callable = callable

    def __get__(self, instance, objtype):
        if instance is None:
            return self.callable
        return types.MethodType(self.callable, instance)

so I can do :

B.method = UnboundMethodType(A().method)
B.method() # print both A and B instances

Is there any other way to do that without writing such descriptor ?

TIA

sthenault
  • 14,397
  • 5
  • 38
  • 32
  • Quick, off-topic comment: No need to derive from object in Py3. It's always done implicitly. To check, just `print(anyobject.__mro__)` (=Method resolution order) – cfi Aug 29 '12 at 12:40
  • I believe this is a duplication of [http://stackoverflow.com/questions/10729909/convert-builtin-function-type-to-method-type-in-python-3]. However this question is probably easier to find. Also it is more clear (at least to me), so I'd vote to keep this one... – cfi Aug 29 '12 at 12:56
  • @cfi, true about object inheritance, fixed UnboundMethod code sample. Also you're right that's a similar question as for binding a compiled/builtin function (which has no satisfying answer btw) – sthenault Aug 29 '12 at 13:30
  • 1
    You are missing a line: B.method = types.MethodType(A().method, None, B); b=B(); b.method() # print both A and B instances – Sheena Sep 18 '12 at 18:32

2 Answers2

1
B.method = lambda o: A.method(o,A())

b = B()
b.method()

the line b.method() then calls A.method(b,A()). This means a A is initialized each time. To avoid this:

a = A()
B.method = lambda o: A.method(o,a)

now every time you call b.method() on any instance of B the same instance of A is passed as the second argument.

Sheena
  • 15,590
  • 14
  • 75
  • 113
0

Well, your code doesn't work in Python 2 either, but I get what you are trying to do. And you can use lambda, as in Sheena's answer, or functools.partial.

>>> import types
>>> from functools import partial

>>> class A(object):
...   def method(self, other):
...     print self, other
... 
>>> class B(object): pass
... 
>>> B.method = partial(A().method, A())
>>> B().method()
<__main__.A object at 0x112f590> <__main__.A object at 0x1132190>
Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251