views:

148

answers:

8

Assume you define a class, which has a method which does some complicated processing:

class A(object):
    def my_method(self):
        # Some complicated processing is done here
        return self

And now you want to use that method on some object from another class entirely. Like, you want to do A.my_method(7).

This is what you'd get: TypeError: unbound method my_method() must be called with A instance as first argument (got int instance instead).

Now, is there any possibility to hack things so you could call that method on 7? I'd want to avoid moving the function or rewriting it. (Note that the method's logic does depend on self.)

One note: I know that some people will want to say, "You're doing it wrong! You're abusing Python! You shouldn't do it!" So yes, I know, this is a terrible terrible thing I want to do. I'm asking if someone knows how to do it, not how to preach to me that I shouldn't do it.

A: 

That's what's called a staticmethod:

class A(object):
    @staticmethod
    def my_method(a, b, c):
        return a, b, c

However in staticmethods, you do not get a reference to self.

If you'd like a reference to the class not the instance (instance implies reference to self), you can use a classmethod:

class A(object):
    classvar = "var"

    @classmethod
    def my_method(cls, a, b, c):
        print cls.classvar
        return a, b, c

But you'll only get access to class variables, not to instance variables (those typically created/defined inside the __init__ constructor).

If that's not good enough, then you will need to somehow pass a "bound" method or pass "self" into the method like so:

class A(object):
    def my_method(self):
        # use self and manipulate the object

inst = A()
A.my_method(inst)

As some people have already said, it's not a bad idea to just inherit one class from the other:

class A(object):
    ... methods ...

class B(A):
    def my_method(self):
        ... use self

newA = B()
xyld
Thanks for the answer, but I said: "Note that the method's logic does depend on `self`.".
cool-RR
A: 

You could just put that method into a superclass of the two objects that need to call it, couldn't you? If its so critical that you can't copy it, nor can you change it to not use self, thats the only other option I can see.

Paul
No good, it's a method which is specific to the class it's defined on.
cool-RR
A: 
>>> class A():
...     me = 'i am A'
... 
>>> class B():
...     me = 'i am B'
... 
>>> def get_name(self):
...     print self.me
... 
>>> A.name = get_name
>>> a=A()
>>> a.name()
i am A
>>> 
>>> B.name = get_name
>>> b=B()
>>> b.name()
i am B
>>> 
rebus
looks so much like monkey patching... would scare me to do that all the time...
xyld
Personaly if i wanted several types of objects to inherit standard API i'd use class inheritance so that both A and B inherit `name` method from some 3rd base class. This is just an example.
rebus
I just think its bad to suggest monkey patching as a "fix"...
xyld
OP's not looking for a reasonable answer - he wants to hack, so you should pretty much cover your eyes for any answer to this question.
Jeremy Brown
Probably so, but the question is can it be done not should it be done.
rebus
+1  A: 

You can't. The restriction has actually been lifted in Python 3000, but I presume you are not using that.

However, why can't you do something like:

def method_implementation(self, x,y):
   # do whatever

class A():
   def method(self, x, y):
        return method_implementation(self, x, y)

If you are really in the mood for python abuse, write a descriptor class that implements the behavior. Something like

class Hack:
   def __init__(self, fn):
       self.fn = fn
   def __get__(self, obj, cls):
       if obj is None: # called staticly
            return self.fn
       else:
            def inner(*args, **kwargs):
                 return self.fn(obj, *args, **kwargs)
            return inner

Note that this is completely untested, will probably break some corner cases, and is all around evil.

Winston Ewert
Thanks for the info about Python 3, that's interesting and I didn't know that.
cool-RR
A: 

Why cant you do this

class A(object):
    def my_method(self,arg=None):
        if (arg!=None):
           #Do Some Complicated Processing with both objects and return something 
        else:
               # Some complicated processing is done here
        return self
anijhaw
+2  A: 
def some_method(self):
    # Some complicated processing is done here
    return self

class A(object):
    my_method = some_method
a = A()

print some_method
print a.my_method
print A.my_method
print A.my_method.im_func
print A.__dict__['my_method']

prints:

<function some_method at 0x719f0>
<bound method A.some_method of <__main__.A object at 0x757b0>>
<unbound method A.some_method>
<function some_method at 0x719f0>
<function some_method at 0x719f0>

It sounds like you're looking up a method on a class and getting an unbound method. An unbound method expects a object of the appropriate type as the first argument.

If you want to apply the function as a function, you've got to get a handle to the function version of it instead.

Matt Anderson
A: 

In Python functions are not required to be enclosed in classes. It sounds like what you need is utility function, so just define it as such:

def my_function(object):
    # Some complicated processing is done here
    return object

my_function(7)
my_function("Seven")

As long as your processing is using methods and attribute available on all objects that you pass to my_function through the magic of duck typing everything will work fine.

Tendayi Mawushe
+4  A: 

Of course I wouldn't recommend doing this in real code, but yes, sure, you can reach inside of classes and use its methods as functions:

class A(object):
    def my_method(self):
        # Some complicated processing is done here
        return 'Hi'

print(A.__dict__['my_method'](7))
# Hi
unutbu
Wow, that is a hack... heh
xyld
I want you to be the father of my children! :)
cool-RR
xyld, I've seen some serious hacks in otherwise respectable packages. This thing is pretty well-mannered.
cool-RR
@cool-RR I've seen some serious hacks too, but this is ridiculous, because its exactly the same as `A.my_method(self)`, you still have to pass in `self`...
xyld
I guess you do side-step the logic that `self` is of type `A` then, but still...
xyld