Attaching a class method to another exisiting class - python

New to python here and I am looking to attach some class, ClassA.methodA to another ClassB as below
def methodA(self, x=None, y=None, z='somevalue', l=None, m=False, **kwds):
... Some logic here....
a = self.getMyInstanceOfClassA() //a is of type ClassA, not ClassB
a.methodA(x,y,z,l,m,**kwds)
ClassB.methodA = methodA
...
h = ClassB()
h.methodA("p1", "p2", m=True)
The goal is to keep the signature of ClassB.methodA the same as it is supposed to be on the actual ClassA.methodA which is accessible on ClassB.getMyInstanceOfClassA() method.
The reason I am doing this is to avoid my user to write this code
h = ClassB()
---the extra logic---
a = h.getMyInstanceOfClassA()
a.methodA(....)
an instead just say
h = ClassB()
h.methodA(....)
and I embed the extra logic inside the new methodA on ClassB.
methodA is something meaningful in our domain and I have to keep its name and exact signature
I have to import both ClassA and ClassB from our internal libs and I can't make ClassB inherit from ClassA.
The point is that methodA is usually not called with all of its arguments and the arguments passed depends on what you want methodA to do. This h.methodA("p1", "p2", m=True) fails with some error complaining about passing too many argument to it.
Am I wrapping the methodA correctly?

I think you would typically just use inheritance or just make that method a function unrelated to the class with one of the inputs being the instance of that class. Or you would just wrap it in a lambda function.
Python: Bind an Unbound Method?
If however you want to take a method and bind it to an instance of a class use something like the below code.
inst = MyClass()
inst.methodA = methodA.__get__(inst, MyClass)

I am not sure what is causing your error (We cannot be sure unless you atleast show the complete traceback or atleast a demo code that reproduces your issue).
But from the code that you have pasted, what you are trying to do would not be possible. Lets take a simple example -
>>> class A:
... def methodA(self, a):
... print(a)
... print("In A")
...
>>> def methodA(self, a, b=None):
... print("In Main")
... if b == None:
... return
... else:
... h = type(self)
... h.methodA(self, a)
...
>>> A.methodA = methodA
>>> h = A()
>>> h.methodA(1,2)
In Main
In Main
I just put the b == None part, so that the code does not do inifinite recursion, but what you are trying to would cause infinite recursion. Why?
Because you have changed methodA to point to a new method at the class level, so even if you call methodA for the class, it would still call the newly bound methodA , not the old one.
If you really do not want the users to call the old methodA directly, one thing you can do is to bind that method to a different name , maybe _methodA , and then bind your new function to methodA. Example -
>>> class A:
... def _methodA(self, a):
... print(a)
... print("In A")
...
>>> def methodA(self, a, b=None):
... print("In Main")
... if b == None:
... return
... else:
... h = type(self)
... h._methodA(self, a)
...
>>> A.methodA = methodA
>>> h = A()
>>> h.methodA(1,2)
In Main
1
In A

Related

Can Monkey patching replace existing function definition in a class?

I know how fierce the SO community is so I'll try my best to keep the question minimal, complete and verifiable.
What I simply want to know is can monkey patching be used to replace the definition of an existing function?
for example:
class A():
def foo():
print '2'
def foo():
print '5'
A.foo = foo
This way doesn't seem to work also as to why I don't just add a new function instead of replacing an existing one, I call these functions in other classes and it is my understanding that monkey patching adds those functions at run-time and I need my python code to run on an Apache spark server which throws an error deeming the calls to that function unreferenced.
So please be nice and help me out or suggest a work around.
Thanks.
Edit: The goal of the code is to print 5 when A.foo is called.
Your only problem is that you aren't defining foo correctly in the first place. It needs to take an explicit argument for the instance calling it.
class A(object):
def __init__(self)
self.x = 2
def foo(self):
print(self.x)
def foo(this):
print(this.x + 3)
A.foo = foo
a = A()
a.foo() # outputs 5 in Python 2 and Python 3
In a very real sense, monkey patching is how classes are created in the first place. A class statement is almost just syntactic sugar for the following code:
def foo(self):
print(self.x)
A = type('A', (object,), {'foo': foo})
del foo
It's not too much of a simplification to image the definition of type being something like
def type(name, bases, d):
new_class = magic_function_to_make_a_class()
new_class.name = name
new_class.bases = bases
for k, v in d.items():
setattr(new_class, k, v)
return new_class
I hope I understand what you are trying to do here. This would work in Python 3:
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo() # Print '2'
foo() # Assign the new method
A.foo() # Prints '5'
In Python 2 however there are several caveats.
print is not a method as it is in Python 3 (see here: Why doesn't print work in a lambda?)
You can't just call unbound messages (see here: In Python, can you call an instance method of class A, but pass in an instance of class B?)
So you have to do it like this:
from __future__ import print_function
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo.__func__() # Print '2'
foo() # Assign the new method
A.foo.__func__() # Prints '5'
Edit:
After seeing your question in the comment I think you actually want something different. Which is this:
class A():
def foo(self):
print '2'
def foo(self):
print '5'
a = A()
a.foo() # Print '2'
A.foo = foo # Assign the new method
a.foo() # Prints '5'
This works just fine in Python 2.
The self is a reference to the current instance the method is bound to. It is not used when you just call something like print which access any properties or methods attached to that instance. But for a different case please have a look at the following example:
class A():
msg = "Some message"
def foo(self):
print self.msg
def bar(self):
self.msg = "Some other message"
a = A()
a.foo() # Print old msg
A.bar = bar # Assign the new method
a.bar() # Assigns new message
a.foo() # Prints new message
Also as chepner points out in a comment under his post:
The name self isn't special; it's just a convention. You could use
this if you really wanted to, and it doesn't need to be the same name
in both functions defined here. What is important is that the first
argument to a function used as an instance method will be a reference
to the calling object. a.foo() is almost exactly the same as A.foo(a)

Storing reference to unbound method

I was trying to store reference to unbound method and noticed that it is being automatically bound. See example below. Is there more elegant way to store unbound method in the class without binding it?
def unbound_method():
print("YEAH!")
class A:
bound_method = unbound_method
unbound_methods = [unbound_method]
a = A()
a.unbound_methods[0]() # succeeds
a.bound_method() # fails
# TypeError: unbound_method() takes 0 positional arguments but 1 was given
This is not a standard "do you know about #staticmethod?" question.
What I'm trying to achieve is provide a way for children of the class provide another handler or certain situations. I do not control the unbound_method itself, it is provided from some library.
def unbound_method_a():
print("YEAH!")
def unbound_method_b():
print("WAY MORE YEAH!")
class A:
bound_method = unbound_method_a
class B(A):
bound_method = unbound_method_b
a = A()
a.bound_method() #fails
# print("YEAH!")
b = B()
b.bound_method() #fails
# print("WAY MORE YEAH!")
It can be achieved by wrapping the unbound method some dummy object like array, or in a bound method, just to drop self reference like this:
def unbound_method_a():
print("YEAH!")
def unbound_method_b():
print("WAY MORE YEAH!")
class A:
def call_unbound_method(self):
return unbound_method_a()
class B(A):
def call_unbound_method(self):
return unbound_method_b()
a = A()
a.call_unbound_method()
# print("YEAH!")
b = B()
b.call_unbound_method()
# print("WAY MORE YEAH!")
Not as far as I know. Would it be so bad if you just replace
a.bound_method()
with
A.bound_method()
?
I can't think of a situation in which the first one can't be replaced by the second one.

bound methods in python

>>> class Class:
... def method(self):
... print 'I have a self!'
...
>>> def function():
... print "I don't..."
...
>>> instance = Class()
>>> instance.method()
I have a self!
>>> instance.method = function
>>> instance.method()
I don't...
Okay the book quotes 'The self parameter (mentioned in the previous section) is, in fact, what distinguishes methods
from functions. Methods (or, more technically, bound methods) have their first parameter
bound to the instance they belong to: you don’t have to supply it. So while you can certainly
bind an attribute to a plain function, it won’t have that special self parameter:'
I am not able to understand what the author is trying to convey here ! I am new to oop in python . Please explain me .
Methods only exist on the class; assigning the function to the instance attribute as your example does creates an instance attribute containing the function, and not a method.
It means that affect of
class A:
def a(self):
print 'a'
def b(self, arg):
print arg
can be roughly represented by:
def A_a(self):
print a
def A_b(self, arg):
print arg
class A:
def __init__(self):
self.a = lambda: A_a(self)
self.b = lambda arg: A_b(self, arg)
So instance.a is not original function a which is written in class A, but another function which calls original with additional self argument.

__init__ or __call__?

When should I use __init__ and when __call__ method ?
I am confused about whether should I use the first or the second.
At the moment I can use them both, but I don't know which is more appropriate.
These two are completely different.
__init__() is the constructor, it is run on new instances of the object.
__call__() is run when you try to call an instance of an object as if it were a function.
E.g: Say we have a class, Test:
a = Test() #This will call Test.__init__() (among other things)
a() #This will call Test.__call__()
A quick test shows the difference between them
class Foo(object):
def __init__(self):
print "init"
def __call__(self):
print "call"
f = Foo() # prints "init"
f() # prints "call"
In no way are these interchangeable
Most likely, you want to use __init__. This is the method used to initialize a new instance of your class, which you make by calling the class. __call__ is in case you want to make your instances callable. That's not something frequently done, though it can be useful. This example should illustrate:
>>> class C(object):
... def __init__(self):
... print 'init'
... def __call__(self):
... print 'call'
...
>>> c = C()
init
>>> c()
call
>>>
A simple code snippet will elaborate this better.
>>> class Math:
... def __init__(self):
... self.x,self.y=20,30
... def __call__(self):
... return self.x+self.y
...
>>> m=Math()
>>> m()
50

Python: Is it possible to construct an instance of a child class from an instance of a parent class?

This may be a terrible idea (feel free to tell me if it is), but I'm exploring the boundaries of Python, and I could see how this could be useful (in fact, I'm looking at a potential case for it right now).
Here is the setup:
---(API File)---
class APINode(object):
def __init__(self, *args, **kwargs):
# initialize some instance variables
def render(self, arg1, arg2):
# do some stuff and return something
def api_function( arg1, arg2 ):
# do some stuff
return APINode(args, kwargs)
---- (My file) ----
class MyNode(APINode):
def render(self, arg1, arg2):
#My override of APINode's render
def my_function( arg1, arg2 ):
api_parent_instance = api_function( arg1, arg2 )
#Can I some how create an instance of MyNode from api_parent_instance here?
I want to modify the output of the api_function slightly, basically just to override the render function in the object it returns. I feel like my options are: (1, yuck) to copy the contents of api_function into my_function, but just construct and return a MyNode instead of an APINode, or (2, maybe?) to just call api_function from my_function, let its do its work--constructing and returning an object of type APINode, and then I can somehow create a MyNode from that object in order to override that one method.
It boils down to: In Python, is it possible to construct an instance of a child class from an instance of a parent class?
(Look familiar or wondering what the actual case is? I'm trying to extend a Django template tag.)
I think you'll be happier with MyNode wrapping APINode, rather than extending it. You can implement your own render() method, and delegate all others to the wrapped APINode. Then you'll be able to create a new MyNode from an existing APINode.
There's no way to make a child instance from a parent instance. The parent instance is an instance of APINode, you can't change an object's class.
Don't do this at home.
>>> class A:
... def hi(self):
... print "I am an A!"
...
>>> class B:
... def hi(self):
... print "I am a B!"
...
>>> a = A()
>>> a.hi()
I am an A!
>>> # Doing this will likely lead to hard to find bugs.
>>> a.__class__ = B
>>> a.hi()
I am a B!
>>>
Monkey patch the API instead!
def render(self, arg1, arg2):
#My override of APINode's render
APINode.render = render
#congratulations, now APINode uses your render function.
This will still likely lead to hard-to-find bugs, but it's a bit cleaner.
Override the allocator.
class B(object):
def __new__(cls, val):
if val:
return D()
return super(B, cls).__new__(cls)
def foo(self):
return 'bar'
class D(object):
def foo(self):
return 'baz'
b1 = B(False)
b2 = B(True)
print b1.foo()
print b2.foo()
This is not something I would recommend, but anyways:
>>> class Monkey(object):
... def eat(self, smth):
... if self.likes(smth):
... print "Yummy!"
... else:
... print "Yuck!"
... def likes(self, smth):
... return smth == "banana"
...
>>> m = Monkey()
>>> m.eat("banana")
Yummy!
>>> m.eat("cheezburger")
Yuck!
>>> def patch(self, smth):
... return True
...
>>> m.likes = type(m.likes)(patch, m.likes, Monkey)
>>> m.eat("cheezburger")
Yummy!
>>>
In your particular case it would look like:
def my_render(self, arg1, arg2):
#My override of APINode's render
def my_function( arg1, arg2 ):
api_parent_instance = api_function( arg1, arg2 )
api_parent_instance.render = type(api_parent_instance.render)(
api_parent_instance,
api_parent_instance.render,
api_parent_instance.__class__)
...
Here is a very simple and safe way of generating a new instance of a child class from a method of the parent class:
class Parent(object):
def __init__(self):
pass
def generate_new_child_object(self):
print "Generating a new object of type " + str(type(self))
return type(self)()
class Child(Parent):
pass
And you can check this in the terminal as follows:
>>> child = Child()
>>> type(child)
<class 'Child'>
>>> generated_child = child.generate_new_child_object()
Generating a new object of type <class 'Child'>
>>> type(generated_child)
<class 'Child'>
I think what you want to do is to look into the super class or something. It's like, a = obj._class_()
I can't fully remember, but you should look into the python docs for that.
Unless that's not what you want at all. But the obj._class_() should spawn a new object of the same class.

Categories

Resources