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'))
Related
I'm writing a Python class A with a method square() that returns a new instance of that class with its first attribute squared. For example:
class A:
def __init__(self, x):
self.x = x
def square(self):
return self.__class__(self.x**2)
I would like to use this method in a subclass B so that it returns an instance of B with x squared but all additional attributes of B unchanged (i. e. taken from the instance). I can get it to work by overwriting square() like this:
class B(A):
def __init__(self, x, y):
super(B, self).__init__(x)
self.y = y
def square(self):
return self.__class__(self.x**2, self.y)
If I don't overwrite the square() method, this little code example will fail because I need to pass a value for y in the constructor of B:
#test.py
class A:
def __init__(self, x):
self.x = x
def square(self):
return self.__class__(self.x**2)
class B(A):
def __init__(self, x, y):
super(B, self).__init__(x)
self.y = y
#def square(self):
# return self.__class__(self.x**2, self.y)
a = A(3)
a2 = a.square()
print(a2.x)
b = B(4, 5)
b2 = b.square()
print(b2.x, b2.y)
$ python test.py
9
Traceback (most recent call last):
File "test.py", line 20, in <module>
b2 = b.square()
File "test.py", line 6, in square
return self.__class__(self.x**2)
TypeError: __init__() takes exactly 3 arguments (2 given)
Overwriting the method once isn't a problem. But A potentially has multiple methods similar to square() and there might be more sub(sub)classes. If possible, I would like to avoid overwriting all those methods in all those subclasses.
So my question is this:
Can I somehow implement the method square() in A so that it returns a new instance of the current subclass with x squared and all other attributes it needs for the constructor taken from self (kept constant)? Or do I have to go ahead and overwrite square() for each subclass?
Thanks in advance!
I'd suggest implementing .__copy__() (and possibly .__deepcopy__ as well) methods for both classes.
Then your squared can be simple method:
def squared(self):
newObj = copy(self)
newObj.x = self.x **2
return newObj
It will work with inheritance, assuming all child classes have correctly implemented __copy__ method.
EDIT: fixed typo with call to copy()
Full working example:
#test.py
from copy import copy
class A:
def __init__(self, x):
self.x = x
def square(self):
newObj = copy(self)
newObj.x = self.x **2
return newObj
def __copy__(self):
return A(self.x)
class B(A):
def __init__(self, x, y):
super(B, self).__init__(x)
self.y = y
def __copy__(self):
return B(self.x, self.y)
a = A(3)
a2 = a.square()
print(a2.x)
b = B(4, 5)
b2 = b.square()
print(b2.x, b2.y)
check if the object contains y then return the right class instance:
class A:
x: int
def __init__(self, x):
self.x = x
def square(self):
if hasattr(self, 'y'):
return self.__class__(self.x ** 2, self.y)
return self.__class__(self.x**2)
class B(A):
y: int
def __init__(self, x, y):
super(B, self).__init__(x)
self.y = y
# def square(self):
# return self.__class__(self.x**2, self.y)
class A:
def __init__(self, x, y):
self.x = x
self.y = y
def method(self):
return A(self.x + 1, self.y + 1)
def method2(self, f):
if self.f().x > 3:
return True
a = A(1, 2)
y = a.method2(a.method())
print(y)
The error occurs on the line with
if self.f().x > 3:
I don't understand why it says it has no attribute and not method.
Let's go through the call to a.method2.
You call a.method(). This returns a new instance of A
This new instance is passed to a.method2 as the local variable f
You then attempt to call a.f (through self), but f is an instance
You aren't calling self.<some_function>, you are trying to say that an instance of A has an attribute that is also an instance of A, which is not the case. It's effectively doing:
a.A(a.x+1, a.y+1).x
Which raises your error. Yes, an instance of A has the attribute x, but no instance of A has an attribute matching this new instance. It's not totally clear what you are trying to accomplish. If you are trying to test the value of the attribute on a new instance, you might just do:
class A:
def __init__(self, x
self.y = y
def method(self):
return A(self.x + 1, self.y + 1)
def method2(self):
# just check the value itself
if self.x > 3:
return True
else:
return False
a = A(1, 2)
# b is a new instance, you shouldn't be testing values of b
# via some function in a, because really this function
# exists in all instances, including b
b = a.method()
# so check b.x through the instance b instead
b.method2()
False
The problem relies just on mixing "self." and "f()". What method() returns and method2() should expect is a class object, so you just have to use it exactly as that.
This way it perfectly works:
class A:
def __init__(self, x, y):
self.x = x
self.y = y
def method(self):
return A(self.x + 1, self.y + 1)
def method2(self, f):
return f.x > 3
a = A(1, 2)
y = a.method2(a.method())
print(y)
What's the difference between self.x+self.y and x+y in the code below?
class m2:
x, y = 4, 5
def add(self, x, y):
return self.x + self.y
def add2(self, x, y):
return x + y
>>> x = m2()
>>> print "x.add(self.x + self.y = )", x.add(1, 2)
x.add(self.x + self.y = ) 9
>>> print "x.add2(x + y = )", x.add2(1, 2)
x.add2(x + y = ) 3
Why does self.x + self.y return 9 vs x + y returns 3?
In add you are calling the class variables and ignoring the method arguments x and y.
class m2:
# these variables are class variables and are accessed via self.x and self.y
x, y = 4, 5
def add(self, x, y):
return self.x + self.y # refers to 4 and 5
def add2(self, x, y):
return x + y # refers to input arguments x and y, in your case 1 and 2
When defining x and y in the class scope it makes them class variables. They are part of the the class m2 and you don't even need to create an instance of m2 to access them.
print m2.x, m2.y
>> 4, 5
However, you are also able to access them via an instance as if they were instance variables like this:
m = m2()
print m.x, m.y
>> 4, 5
The reason behind this is that the interpreter will look for instance variables with names self.x and self.y, and if they are not found it will default to class variables.
Read more about class attributes in the python documentation.
The difference is that when you use self you refer to the member of the instance of your class
When you use X and Y dirrectly you refer to the parameter that you use in your function
This is a simplification of your class
class m2:
x_member1, y_member2 = 4, 5
def add(self, x_parameter1, y_parameter2 ):
return self.x_member1+ self.y_member2
def add2(self, x_parameter1, y_parameter2 ):
return x_parameter1 + y_parameter2
When a class method is called, the first argument (named self by convention) is set to the class instance. When the method accesses attributes of self, it is accessing those attributes in the class instance, and their values persist in that instance.
On the other hand, if a class method accesses bare variables, those variables are strictly local to those methods and their values do not persist across calls to class methods of that instance.
class m2:
x, y = 4, 5 #This are class attributes
def add(self, x, y ):
return self.x + self.y # This are instance variables
def add2(self, x, y ):
return x + y # This are local variables
Class variables are common to each instance of the class. Instance variables are only avaible to that instance. And local variables are only avaible in the scope of the function.
In add, when you do self.x it's refering to the class variable x cause it's also part of the instance. In add2 it's refering to local variables
The same results could be achieved if those methods were class methods or static methods (With proper adjustments)
Class method:
class m2:
x, y = 4, 5
#classmethod
def add(cls, x, y):
return cls.c + cls.y #Here you're calling class attributes
#classmethod
def add2(cls, x, y):
return x + y
Results:
>>> m.add(1,2)
9
>>> m.add2(1,2)
3
Static method:
class m2:
x, y = 4, 5
#staticmethod
def add(x, y):
return m2.c + m2.y #Here you need to call the class attributes through the class name
#staticmethod
def add2(x, y):
return x + y
Results:
>>> m2.add(1,2)
9
>>> m2.add2(1,2)
3
x and y will be local by default. The self.x and self.y are persisted in that instance, x and y will only be there locally.
class Dog():
def __init__(self):
x = "local"
self.y = "instance"
d = Dog()
print(d.y)
#=> instance
print(d.x)
#=> AttributeError: Dog instance has no attribute 'y'
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.
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)