I am trying to automatically update class variables that are in a fix relation. E.g.
class vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
self.r = (x**2+y**2+z**2)**0.5
self.theta = tan((x**2+y**2)**0.5/z)
self.phi = tan(y/x)
If I change the value x of an instance of this class, I want to update the radius and the angles automatically. And if I change an angle or the radius, I want to update the x,y,z components automatically. Is there any way to do this?
Edit:
Okay I have the following solution now. Please correct me if there is a mistake or not conventional what I did.
from math import tan, cos, sin
class Vector:
def __init__(self, x, y, z):
self._x = x
self._y = y
self._z = z
self._r = (self._x**2+self._y**2+self._z**2)**0.5
self._theta = tan((self._x**2+self._y**2)**0.5/self._z)
self._phi = tan(self._y/self._x)
#property
def x(self):
return self._x
#x.setter
def x(self, new_x):
self._x = new_x
self._r = (self._x**2+self._y**2+self._z**2)**0.5
self._theta = tan((self._x**2+self._y**2)**0.5/self._z)
self._phi = tan(self._y/self._x)
#property
def y(self):
return self._y
#y.setter
def y(self, new_y):
self._y = new_y
self._r = (self._x**2+self._y**2+self._z**2)**0.5
self._theta = tan((self._x**2+self._y**2)**0.5/self._z)
self._phi = tan(self._y/self._x)
#property
def z(self):
return self._z
#z.setter
def z(self, new_z):
self._z = new_z
self._r = (self.x**2+self.y**2+self.z**2)**0.5
self._theta = tan((self._x**2+self._y**2)**0.5/self._z)
self._phi = tan(self._y/self._x)
#property
def r(self):
return (self._x**2+self._y**2+self._z**2)**0.5
#r.setter
def r(self, new_r):
self._r = new_r
self._x = self._r*cos(self._theta)*cos(self._phi)
self._y = self._r*cos(self._theta)*sin(self._phi)
self._z = self._r*sin(self._theta)
#property
def theta(self):
return tan((self._x**2+self._y**2)**0.5/self._z)
#theta.setter
def theta(self, new_theta):
self._theta = new_theta
self._x = self._r*cos(self._theta)*cos(self._phi)
self._y = self._r*cos(self._theta)*sin(self._phi)
self._z = self._r*sin(self._theta)
#property
def phi(self):
return tan(self._y/self._x)
#phi.setter
def phi(self,new_phi):
self._phi = new_phi
self._x = self._r*cos(self._theta)*cos(self._phi)
self._y = self._r*cos(self._theta)*sin(self._phi)
self._z = self._r*sin(self._theta)
You are looking for the #property decorator, which sets an object's variable via a function statement.
from math import tan
class Vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
#property
def r(self):
return (self.x**2+self.y**2+self.z**2)**0.5
#property
def theta(self):
return tan((self.x**2+self.y**2)**0.5/self.z)
#property
def phi(self):
return tan(self.y/self.x)
Therefore,
v = Vector(1, 2, 3)
v.phi # -2.185039863261519
You could rewrite your class as below
import math
class Vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
#property
def radius(self):
return (self.x**2+self.y**2+self.z**2)**0.5
#property
def theta(self):
return math.tan((self.x**2+self.y**2)**0.5/self.z)
#property
def phi(self):
return math.tan(self.y/self.x)
Related
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)
class A(object):
def __init__(self, x):
self.x = x
def f(self, x):
return 2*x
def g(self, x):
return self.f(x)
class B(A):
def g(self, y):
return 3*y + self.x
class C1(B):
def __init__(self, x, y):
B.__init__(self,x)
self.y = y
def f(self, x):
return self.x + self.y
class C2(B):
def __init__(self, x, y):
B.__init__(self,x)
self.y = y
def f(self, x):
return x + self.x + self.y
a = A(5)
b = B(2)
c1 = C1(3,5)
c2 = C2(3,5)
When I do "What does the expression c2.f(4) evaluate to?", I was not sure where self.x in the f function in class C2 points to.
Could you give me some suggestions?
c2.f(4) makes 12. The value of x in function f is 4 because that is the argument in c2.f(4). The value of c2's self.x is 3 because C2 inherits from B, which inherits from A, where the line self.x = x occurs. In this line, x is what is entered in the line c2 = C2(3,5) and because it is assigned to self.x, c2's self.x is 3. Because of the line self.y = y in class C2, the instance c2's y value is what is entered in the line c2 = C2(3,5), 5. 4 + 3 + 5 makes 12.
I'm trying to initialize sT from an imported module. And getting the error:
sT = SierpinskiTriangle(self.dimensions, 50000, 0.5, vertices)
TypeError: SierpinskiTriangle() takes exactly 1 argument (4 given)
and I'm not really sure why or what I've done wrong.
sT = SierpinskiTriangle(self.dimensions, 50000, 0.5, vertices)
And I've imported this from another file:
class Fractal(Canvas, Point):
def __init__(self, dimensions, num_points, ratio, vertices):
self.dimensions = dimensions
self.num_points = num_points
self.r = ratio
self.vertices = vertices
def frac_x(self, r):
return int((self.dimensions["max_x"] - \
self.dimensions["min_x"]) * r) + \
self.dimensions["min_x"]
def frac_y(self, r):
return int((self.dimensions["max_y"] - \
self.dimensions["min_y"]) * r) + \
self.dimensions["min_y"]
def SierpinskiTriangle(Fractal):
def __init__(self, dimensions, num_points, ratio, vertices):
Fractal.__init__(self, dimensions, num_points, ratio, vertices)
Edit, here's the Point class:
class Point(object):
def __init__(self, x = 0.0, y = 0.0):
self.x = float(x)
self.y = float(y)
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
#property
def y(self):
return self._y
#y.setter
def y(self, value):
self._y = value
def dist(self, secondPoint):
#get the self x values from self.x and the values
#of the seecond point from secondPoint.x
#same with y
dist = math.sqrt(((self.x - secondPoint.x)**2)+ ((self.y - secondPoint.y)**2))
return dist
def midpt(self, secondPoint):
#same as the dist
midpointx = (self.x + secondPoint.x)/2
midpointy = (self.y + secondPoint.y)/2
midpoint = Point(midpointx,midpointy)
return midpoint
def __str__(self):
return "({},{})".format(self.x,self.y)
I hope this also helps clarify things. I don't have the Canvas class because it is a part of Tkinter.
You used def instead of class for SierpinskiTriangle which means it only takes one argument (Fractal) instead of treating Fractal as its super class.
Change that to class like below and it will take 4 arguments.
class SierpinskiTriangle(Fractal):
def __init__(self, dimensions, num_points, ratio, vertices):
Fractal.__init__(self, dimensions, num_points, ratio, vertices)
I have the following code which has 2 classes- A point and a circle:
import math
class Point:
"""Two-Dimensional Point(x, y)"""
def __init__(self, x=0, y=0):
# Initialize the Point instance
self.x = x
self.y = y
def __iter__(self):
yield self.x
yield self.y
def __iadd__(self, other):
self.x = self.x + other.x
self.y = self.y + other.y
return self
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __mul__(self, other):
mulx = self.x * other
muly = self.y * other
return Point(mulx, muly)
def __rmul__(self, other):
mulx = self.x * other
muly = self.y * other
return Point(mulx, muly)
#classmethod
def from_tuple(cls, tup):
x, y = tup
return cls(x, y)
def loc_from_tuple(self, tup):
# self.x=t[0]
# self.y=t[1]
self.x, self.y = tup
#property
def magnitude(self):
# """Return the magnitude of vector from (0,0) to self."""
return math.sqrt(self.x ** 2 + self.y ** 2)
def distance(self, self2):
return math.sqrt((self2.x - self.x) ** 2 + (self2.y - self.y) ** 2)
def __str__(self):
return 'Point at ({}, {})'.format(self.x, self.y)
def __repr__(self):
return "Point(x={},y={})".format(self.x, self.y)
class Circle(Point):
"""Circle(center, radius) where center is a Point instance"""
def __init__(self, center= Point(0,0), radius=1):
# Point.__init__(self,center)
self.center = 1 * center
self.radius = radius
# if not isinstance(center,Point):
# raise TypeError("The center must be a Point!")
#property
def center(self):
return self._center
#center.setter
def center(self, _center):
self._center = _center
if (isinstance(self._center, Point) is False):
raise TypeError("The center must be a Point!")
def __getitem__(self,item):
return self.center[item]
def __add__(self,other):
return Circle(
Point(self.center.x + other.center.x, self.center.y+other.center.y),
self.radius + other.radius)
#classmethod
def from_tuple(cls, center,radius):
return cls(center, radius)
#property
def radius(self):
return self._radius
#radius.setter
def radius(self, radius):
if radius < 0:
raise ValueError('The radius cannot be negative')
self._radius = radius
#property
def area(self):
"""Calculate and return the area of the Circle"""
return math.pi * self.radius ** 2
#property
def diameter(self):
"""Calculate and return the diameter of the Circle"""
return self.radius * 2
def __str__(self):
return "Circle with center at ({0}, {1}) and radius {2}".format(self.center.x, self.center.y, self.radius)
def __repr__(self):
return "Circle(center=Point({0}, {1}), radius={2})".format(self.center[0],self.center[1],self.radius)
The normal addition works as expected but the += does not. The following is the expected output.
circle1 = Circle(radius=2.5, center=Point(1, 1))
circle2 = Circle(center=Point(2, 3), radius=1)
id1 = id(circle1)
circle1 += circle2
print(circle2)
Circle(center=Point(2, 3), radius=1)
print(circle1)
Circle(center=Point(3,4), radius=3.5)
print(id1 == id(circle1))
True
When I try to run this, I get the following error:
Traceback (most recent call last):
File "/Users/ayushgaur/Downloads/HW8_files (1)/shapes.py", line 206, in
circle1 += circle2
File "/Users/ayushgaur/Downloads/HW8_files (1)/shapes.py", line 18, in iadd
self.x = self.x + other.x
AttributeError: 'Circle' object has no attribute 'x
Can anyone see why this is happening?
class Circle(Point): means that the class Circle is inherited from the class Point and therefore the function __iadd__ of Point too. I do not see why you would want to inherit Circle from Point.
I would suggest removing the inheritance, i.e. having simply class Circle: and defining a function __iadd__ for circle which is the function that defines what circle1 += circle2 does.
Circle inherited Point's __iadd__() method, used when += is called.
You may want to override the __iadd__() method by:
def __iadd__(self, other):
return self.add(self, other)
I have to use a class. I have to make sure that x and y are properties.
If the values provided are not convertible to an integer, raise an AttributeError. If we give a value less than 0 to x or y, it is assigned the value 0.
If we give a value greater than 10 to x or y, it is assigned the value 10.
Here is my code:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def getx(self):
x=int()
return self._x
def gety(self):
y=int()
return self._y
if x>=0:
return 0
else if x<=10:
return 10
I want to obtain this:
p = Point(1,12)
print(p.x, p.y) # output "1 10"
p.x = 25
p.y = -5
print(p.x, p.y) # output "10 0"
What are you looking for is clamp() function, which takes 3 arguments: value, desired minimal value and desired maximal value.
Properties are defined by the #property decorator. For testing if the value assigned to property is number I use numbers module. Here is sample code:
import numbers
def clamp(v, _min, _max):
return max(min(v, _max), _min)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
#property
def x(self):
return self.__x
#x.setter
def x(self, value):
if not isinstance(value, numbers.Number):
raise AttributeError()
self.__x = clamp(int(value), 0, 10)
#property
def y(self):
return self.__y
#y.setter
def y(self, value):
if not isinstance(value, numbers.Number):
raise AttributeError()
self.__y = clamp(int(value), 0, 10)
p = Point(1,12)
print(p.x, p.y) # output "1 10"
p.x = 25
p.y = -5
print(p.x, p.y) # output "10 0"