I have following code:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
#classmethod
def zero(cls):
return cls(0, 0)
point = Point.zero()
I am not getting the expected output: Point(0, 0).
you are getting the correct Point object. To confirm, print type(point) and print point.x or point.y. But its representation defaults to what object.__repr__ provides(all classes inherit this from object class). Implement your own __str__ or __repr__. (See the difference here):
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
#classmethod
def zero(cls):
return cls(0, 0)
def __repr__(self) -> str:
return f"Point{self.x, self.y}"
point = Point.zero()
print(point)
You do, but what you generate is a Class Object:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
#classmethod
def zero(cls):
return cls(0, 0)
origin = Point.zero()
origin.x -> 0
origin.y -> 0
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)
I am trying to Implement the set_x, set_y, init, and str methods in the class Vector above, the output of this test should be:
#Vector: x=4, y=4
#Vector: x=5, y=5
#Vector: x=3, y=7
#Vector: x=3, y=7
.
class Vector:
def __init__(self, x, y): self.x = x self.y = y
def set_x(self,x): set_x = x
def set_y(self,y): set_y = y
def __str__(self): return ("Vector: x=%s, y=%s", set_x, set_y)
#__init__ and __str__ v1=Vector(4,4) print(v1)
#Important Remark
#v1.x,v1.y =4,4 # should return an error since x and y are private
# test set_x and set_y v1.set_x(5) v1.set_y(5) print(v1)
v1.set_x(1) v1.set_y(9) print(v1)
# test __init__ again print(Vector(1,9))
I believe this is what you are trying to do:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def set_x(self, x):
self.x = x
def set_y(self, y):
self.y = y
def __str__(self):
return f"Vector: x={self.x}, y={self.y}"
v1 = Vector(1, 9)
print(v1)
I'm trying to define a class that has an instance of itself as a class variable so I can reference a common instance of it all over the place.
How can I get something like this to work?
class Point():
ORIGIN = Point()
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p0 = Point.ORIGIN
p1 = Point(3,4)
distance = (p1.x*p1.x + p1.y*p1.y) ** .5
print(distance)
You can add the class attribute after the class has been created:
class Point():
def __init__(self, x=0, y=0):
self.x = x
self.y = y
Point.ORIGIN = Point()
You can probably also make it work so that the origin is created lazily via descriptors, or you can probably do something funky using a metaclass -- but that seems unlikely to be worth your while.
You could use a meta class:
>>> class SingletonMeta(type):
... def __init__(cls, name, bases, dct):
... cls.ORIGIN = cls()
...
>>> class Point(metaclass=SingletonMeta):
... def __init__(self, x=0, y=0):
... self.x = x
... self.y = y
...
>>> p0 = Point.ORIGIN
>>> p1 = Point(3,4)
>>> p0
<__main__.Point object at 0x110b7e7b8>
>>> p0.x, p0.y
(0, 0)
Simply create class variables that represent the values you want instead of encapsulating those values in an instance:
class Point:
x = 0
y = 0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
x,y = Point.x, Point.y
p1 = Point(3,4)
distance = ((p1.x-x)**2 + (p1.y-y)**2) ** .5
print(distance) # prints 5.0
Or, better yet:
class Point:
x = 0
y = 0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def distance(self, other=None):
if other is None:
x,y = Point.x, Point.y
else:
x,y = other.x, other.y
return ((self.x-x)**2 + (self.y-y)**2) ** .5
And then you can do this:
>>> p1 = Point(3,4)
>>> p1.distance()
5.0
>>> p1.distance(Point(3,5))
1.0
I'm having trouble on how to implement property to protect attributes.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def set_x(self, x):
if '_x' in dir(self):
raise NotImplementedError("Cannot change x coordinate")
else:
self._x = x
def get_x(self):
return self._x
#I beleive my mistake is here. I'm not sure if I'm implementing this correctly
x = property(get_x, set_x, None, None)
So I want to prevent any user from changing the x-coordinate. My question is, how do I get python to redirect the user to the set_x() and get_x() methods? I've tried running this code in terminal and whenever I apply the following, the point changes.
p = point(3, 4)
p.x = 5 #x is now 5
You only need this much:
class Point:
def __init__(self, x, y):
self._x = x
self.y = y
def get_x(self):
return self._x
x = property(get_x)
You can set the hidden field self._x in your init, then you don't need a setter for x at all. And have get_x return self._x rather than self.x so it doesn't try and call itself.
You can use the #property decorator to do this even more succinctly.
class Point:
def __init__(self, x, y):
self._x = x
self.y = y
#property
def x(self):
return self._x
The following code works on both python2.x and python3.x:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def set_x(self, x):
if '_x' in dir(self):
raise NotImplementedError("Cannot change x coordinate")
else:
self._x = x
def get_x(self):
return self._x
x = property(get_x, set_x, None, None)
p = Point(2, 3)
print(p.x) # 2
p.x = 6 # NotImplementedError
Pretty much all I did was inherit from object (to get it to work on python2.x) and use the name Point rather than point (which would have been a NameError before).
There are other things you can do to clean it up a bit (e.g. khelwood's suggestion of just writing the getter -- or DSM's suggestion of using hasattr instead of '_x' in dir(self)).
Note, if you really just want a type that takes an x and y arguments that you want to be immutable -- Maybe you should consider using a colledctions.namedtuple
from collections import namedtuple
Point = namedtuple('Point', 'x,y')
p = Point(2, 3)
p.x # 2
p.y # 3
p.x = 6 # AttributeError: can't set attribute
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