Let's take a simple class as an example:
class Vector:
def __init__(self):
self.x = 1
self.y = 1
self.z = 1
What I would like is to give this class a variable called sum such that when I do
v = Vector()
v.sum
I am given the sum x+y+z (in this case 3). Of course I can easily just make a class method that does this, but then I would have to write v.sum() instead of v.sum. Is there any way to hide the fact that the class actually calls a function when asking for a variable?
Thanks in advance.
class Vector(object): # subclass object for new style class
def __init__(self):
self.x = 1
self.y = 1
self.z = 1
#property
def sum(self):
return self.x + self.y + self.z
>>> v = Vector()
>>> v.sum
3
http://docs.python.org/2/library/functions.html#property
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)
From an existing code, I need to create instance from a class within another class while lots of information that are needed for initializing the called class, are contained in the caller one.
A way to pass some attributes of a caller class to the called class can be like in the following example passing self as argument and it does what exactly is expected, bu I wondered if it is the correct or whether is there a better way to do so?
class A:
def __init__(self):
self.x = 1
self.y = 10
self.myObj = B(self)
class B:
def __init__(self, Obj_from_A):
self.i = None
self.j = None
self.v= Obj_from_A.x
self.w = Obj_from_A.y
A_obj = A()
print(A_obj.myObj.v, A_obj.myObj.w)
Output:
1 10
Your class does what you think it is doing, except when it might not.
(btw your code does not run: you don't define B_Obj)
See the extra code I've added at the end:
class A:
def __init__(self):
self.x = 1
self.y = 10
self.myObj = B(self)
class B:
def __init__(self, Obj_from_A):
self.i = 0
self.j = 0
self.v= Obj_from_A.x
self.w = Obj_from_A.y
A_obj = A()
print(A_obj.myObj.v, A_obj.myObj.w)
A_obj.x = 2 # Now update the x member
print(A_obj.x, A_obj.myObj.v, A_obj.myObj.w)
Output:
1 10
2 1 10
Here A_obj.x has changed, but the instance of B has held onto the previous values.
I'm using a helper method in my class to modify an attribute, and can see several ways to do this. Are any of the following helper and associated methods preferred or avoided for good reason?
class Test(object):
def __init__(self, x, y):
self.x = x
self.y = y
def _x_helper1(self):
self.x += self.y
def method1(self):
# some other code...
self._x_helper1()
def _x_helper2(self, y):
# some other code...
self.x += y
def method2(self):
# some other code...
self._x_helper2(self.y)
def _x_helper3(self, y):
# some other code...
return y
def method3(self):
# some other code...
self.x += self._x_helper3(self.y)
This example is way too abstract.
Nothing is wrong with just adding obj.x + obj.y. If you need to mutate object's state, and you mutate based on attributes only, use
def mutate(self):
self.x += self.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'
In my example below in Python, object x 'has-an' object y. I'd like to be able to invoke methods of x from y.
I'm able to achieve it using #staticmethod, however I'm discouraged to do that.
Is there any way(s) to reference the whole Object x from Object y?
class X(object):
def __init__(self):
self.count = 5
self.y = Y() #instance of Y created.
def add2(self):
self.count += 2
class Y(object):
def modify(self):
#from here, I wanna called add2 method of object(x)
x = X()
print x.count
>>> 5
x.y.modify()
print x.count
>>> # it will print 7 (x.count=7)
Thanks in advance.
You need to store a reference to the object which has the instance of a Y object:
class X(object):
def __init__(self):
self.count = 5
self.y = Y(self) #create a y passing in the current instance of x
def add2(self):
self.count += 2
class Y(object):
def __init__(self,parent):
self.parent = parent #set the parent attribute to a reference to the X which has it
def modify(self):
self.parent.add2()
Example usage:
>>> x = X()
>>> x.y.modify()
>>> x.count
7
Maybe it's possible for you to use class inheritance? For example:
class X(object):
def __init__(self):
self.count = 5
def add2(self):
self.count += 2
class Y(X):
def __init__(self):
super(Y, self).__init__()
def modify(self):
self.add2()
y = Y() # We now create an instance of Y which is a child class of 'super' class X
y.modify()
print(y.count) # 7