I am trying to learn python monkey patching. I have a simple example where I am trying to monkey patch just a single instance rather than the class itself.
My code:
# add.py
import types
class Math(object):
def __init__(self):
self.name = ''
def add(self, x, y, name):
self.name = name
print 'calling from ', self.name
return x + y
def monkey_patch(self):
add = self.add
def squared_sum(x, y):
return x**2 + y**2
add = types.MethodType(squared_sum, self)
if __name__ == '__main__':
math = Math()
print math.add(3, 4, 'before monkey_patching')
math.monkey_patch()
print math.add(3, 4, 'after monkey_patching')
Expected Output:
calling from before monkey_patching
7
calling from after monkey_patching
25
Generated Output:
calling from before monkey_patching
7
calling from after monkey_patching
7
Can someone point out where I am going wrong. And also how can I monkey patch the add method when I am doing it from a different file i.e. When I import Math class from add.py in a different file, how can I monkey patch it's add method.
Your code doesn't do what you think it does:
def monkey_patch(self):
add = self.add # add now points to self.add
def squared_sum(x, y):
return x**2 + y**2
add = types.MethodType(squared_sum, self) # add now points to squared_sum
# method ends, add and squared_sum are abandoned
This doesn't actually change self.add. Also, squared_sum doesn't take self or name arguments, unlike add, and doesn't have the print that add does. To make this work fully, do:
def monkey_patch(self):
def squared_sum(self, x, y, name):
self.name = name
print 'calling from ', self.name
return x**2 + y**2
self.add = types.MethodType(squared_sum, self)
To patch outside the class definition:
math = Math()
def func(self, x, y, name):
return x ** y
math.add = types.MethodType(func, math)
Related
I want to be able to repr() on a class in python which has functions stored in the class's variables so I can reproduce the same functions later when I eval() said output.
Here's an example to illustrate my problem:
class Example:
def __init__(self, func):
self.func = func
def __repr__(self):
return repr(self.func)
def add(x, y):
return x + y
example = Example(add)
print(repr(example))
When I run that code, the output I get is:
<function add at 0x7f6ea0e96e18>
Is there any way of making a repr() which would output something that can then be eval()ed to a callable function. Ideally, I'd like an output like:
def add(x, y): return x + y
You can do it with Python's inspect module:
import inspect
class Example:
def __init__(self, func):
self.func = func
def __repr__(self):
return inspect.getsource(self.func)
def add(x, y):
return x + y
example = Example(add)
print(repr(example))
Output:
def add(x, y):
return x + y
I've imported a package that provides me with a class and a wrapper function that creates an instance of that class.
For example:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
def print_a(self):
print(self.a)
def print_b(self):
print(self.b)
def makeFoo(x, y):
a = x + y
b = x - y
return Foo(a, b)
I want to have a similar class NamedFoo, that has the same properties/methods, also has a name property, and with a constructor that calls makeFoo. I figure that this should be solved using inheritance, with NamedFoo being a subclass of Foo. However, I don't know how to make the NamedFoo constructor utilize makeFoo correctly:
class NamedFoo(Foo):
def __init__(self, x, y, name):
# ???
# Foo = makeFoo(x, y) ??
# self.Foo = makeFoo(x, y) ??
self.name = name
def printName(self):
print(self.name)
Example data:
myNamedFoo = NamedFoo(2,5,"first")
myNamedFoo.print_a() # (From makeFoo: a = x + y) ==> 2 + 5 = 7
myNamedFoo.print_b() # (From makeFoo: a = x - y) ==> 2 - 5 = -3
I'm not too familiar with object-oriented programming, so I might just be using the wrong search terms, but I haven't found anything similar to what I need. Is this possible, and if so how can I do it?
I'm also not sure if this is an X/Y problem, but here are the alternatives I've considered and why I don't think they're ideal:
Composition of Foo and the property name: It's ugly and doesn't seem right.
Manually adding the name property to each Foo object, and perhaps wrapping it in a function: Doesn't quite have the elegance of a one liner constructor.
Rewriting the constructor for the Foo class, to have the same code as what's in makeFoo: makeFoo is rather complex and needs to do a lot of setup, and this would in any case lead to code duplication
In the NamedFoo constructor, create an instance of the Foo class from the makeFoo wrapper function. Pass this instance's attributes to the super().__init__.
class NamedFoo(Foo):
def __init__(self, x, y, name):
_foo = makeFoo(x,y) # use the wrapper to handle complex logic from input params
super().__init__(_foo.a,_foo.b) # pass the properly derived Foo attributes to the superclass constructor
self.name = name
This way, we're instantiating NamedFoo from whatever magic happens within the makeFoo function. Pass your x and y to that, which creates a throwaway Foo instance (so we can have it properly constructed with whatever complex logic resides in the helper function). The final NamedFoo class is then instantiated from the Foo constructor.
i think this should work..
class Foo:
def __init__(self,a,b):
self.a = a + b
self.b = a - b
def print_a(self):
print(self.a)
def print_b(self):
print(self.b)
class NamedFoo(Foo):
def __init__(self,a,b,name):
super().__init__(a,b)
self.name = name
def main():
example = NamedFoo(2,5,"first")
example.print_a()
example.print_b()
main()
this prints out
7
-3
or if you really want to use a function to create self.a and self.b use this:
class Foo:
def __init__(self, a, b):
self.a, self.b = make_foo(a,b)
def print_a(self):
print(self.a)
def print_b(self):
print(self.b)
class NamedFoo(Foo):
def __init__(self, a,b,name):
super().__init__(a,b)
self.name = name
def make_foo(x,y):
return x+y, x-y
def main():
example = NamedFoo(2,5,"first")
example.print_a()
example.print_b()
main()
I am currently playing around with classes and functions since i am not familiar with python and i would like to know how i can get addy(self, addx) to call addx.
class test:
def __init__(self, x):
self.x = x
def addx(self):
y = self.x + 10
return y
def addy(self, addx):
z = addx() + 10
return z
one = test(1)
print(one.addy())
line 15, in print(one.addy()) TypeError: addy() missing 1
required positional argument: 'addx' Process finished with exit code 1
You need to call self from within a class method.
self.addx()
Also the addx parameter on this line shouldn't be there:
def addy(self, addx):
I think this is what you are going for:
class test:
def __init__(self, x):
self.x = x
def addx(self):
y = self.x + 10
return y
def addy(self):
z = self.addx() + 10
return z
one = test(1)
print(one.addy())
You've overcomplicated things by wrapping it in a class. Take it out and it'll work (mostly) the way you expect.
def add10(x):
return x+10
def add20(x):
return add10(add10(x))
Since you've wrapped it in the class you've complicated the namespace. It's no longer called addx or addy, so using those names throws a NameError. You have to use the qualified name instead.
class FooBar():
def __init__(self):
self.x = 10
def addx(self):
return self.x + 10 # Note the `self.` before the attribute...
def addy(self):
return self.addx() + 10 # ...and also before the method name.
Methods are always passed their owning object as a first argument when called, which is why we've got def addx(self): but then call with self.addx()
If you are attempting to relate addx in the signature of addy to the method addx, you can pass the string name of the method and use getattr:
class Test:
def __init__(self, x):
self.x = x
def addx(self):
y = self.x + 10
return y
def addy(self, func):
z = getattr(self, func)() + 10
return z
s = Test(3)
print(s.addy('addx'))
I am knew at this and not sure the exact syntax to use to add x,y in python using this class definition
class Add(values):
def __init__(self, x, y):
values.__init__(self, [x, y])
def forward(self):
return self.values[x] + values[1]
I am not able to figure out how to access x,y to add them together. I have tried all the possibilities that I can think of. Thank you.
I think you want a function and not a class.
def add(x, y):
return x+y
If you're sure that this really has to be a class for whatever you're doing, it can look like this:
class Add:
def __init__(self, x, y):
self.x = x
self.y = y
def forward(self):
return self.x+self.y
Then
>>>add(5, 6)
11
>>>a = Add(5, 6)
>>>a.forward()
11
i think that is what you need
class Values():
def __init__(self, x = 0, y=0):
self.x_value = x
self.y_value = y
class Add(Values):
def __init__(self, x = 0, y=0):
Values.__init__(self, x, y)
def forward(self):
return (self.x_value + self.y_value)
add = Add(x = 20, y=20)
print (add.forward())
To add something to other answers, I would say that :
class Add(values):
means that you create class 'Add' who inherits from the class 'values'. Class 'values' must be defined somewhere otherwise you will have the NameError.
More info about inheritance here :
https://docs.python.org/3.6/tutorial/classes.html#inheritance
Actually the answer I was looking for is :
self.x =[0]
self.y = [1]
Thanks for the tries.
This question already has answers here:
Understanding Python super() with __init__() methods [duplicate]
(7 answers)
Closed 8 years ago.
I have a class that looks like this:
#!/usr/bin/env python
class Foo:
def __init__(self, x):
self.x = x
def bar(self):
self.bar1_out = self.x + 5
self.bar2_out = self.x + 1
return (self.bar1_out,self.bar2_out)
def qux(self,myvalue = None):
first, second = myvalue or self.bar()
return first + 3, second + 6
def main():
"""docstring for main"""
f = Foo(5)
mbr_out1, mbr_out2 = f.bar()
print mbr_out1, "\t", mbr_out2
mqx_out1, mqx_out2 = f.qux()
print mqx_out1, "\t", mqx_out2
qout1, qout2 = f.qux((1))
print qout1, "\t", qout2
if __name__ == '__main__':
main()
I saw some implementation that suggest using super
def __init__(self, x):
super(Foo,self).__init__()
self.x = x
def bar(self)
#etc.
My questions are:
What's the use of super(Foo,self).__init__()
How does it differ from self.x=x
How can I make my code top above produce the same result by using super()
How does it differ from self.x=x?
super() is only useful if you subclass:
class Foo(object):
def __init__(self, x):
self.x = x
class Bar(Foo):
def __init__(self, x):
super(Bar, self).__init__(x)
self.initial_status = False
is better than setting self.x = x in Bar's __init__.
The difference is that Bar doesn't need to care about the implementation of Foo.
If you choose to change Foo in a way which sets self.x = 2 * x, then you won't have to change Bar as well (which might even sit in a difference file - failure to see this is almost guaranteed).
In your example, there is no point to use super() as you don't subclass.