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)
Related
I a newbie in Python OOP and I have a problem with the below program. When I run it, it gives me an error AttributeError: 'MyClass' object has no attribute 'sum'. This problem can be fix easily by replace the line sum = self.sum at each function compute_sqrtSum(), compute_SumSquare() and compute_SumCube() by sum = self.compute_Sum(). But if so, every time the program run these three functions, it has to run compute_Sum() once, in total three times. So is there a way that I can access to sum but only run compute_Sum() once?
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
def compute_Sum(self):
sum = self.x + self.y
self.sum = sum
return sum
def compute_sqrtSum(self):
sum = self.sum
sqrt_sum = sqrt(sum)
return sqrt_sum
def compute_SumSquare(self):
sum = self.sum
sum_sq = sum * sum
return sum_sq
def compute_SumCube(self):
sum = self.sum
sum_cb = sum * sum * sum
return sum_cb
user = MyClass(1, 2)
print(user.compute_sqrtSum())
print(user.compute_SumSquare())
print(user.compute_sqrtCube())
To have the attributes computed on-the-fly you could use properties to have a method called automatically to determine the value whenever it's needed. However this can become very slow if the value is accessed frequently either by users of the class or by the class itself if other methods within it also reference it.
A way to avoid that is to make the attributes "lazy" which means they aren't calculated until they're first referenced, but the value is cached so if it's needed again, the cached value is returned instead of the being re-calculated.
In the code below each method will only ever be run once because the lazy_property decorator✶—which isn't a property at all—has the side-effect of also creating an instance attribute of the same name as the class' property, which prevents it from being called again because of the way instance attributes are looked up in Python.
The similar but not the same as #furas' answer. It eliminates a lot of the repetitive code and also make it easy to apply the caching to other attributes as well, so they too, will never be calculated more than once.
✶ Lazily-evaluated Property Pattern in Python. Jun 30, 2013. stevenloria.com. Licensed under CC-BY 4.0 License
def lazy_property(fn):
"""Decorator that makes a property lazy-evaluated."""
attr_name = '_lazy_' + fn.__name__
#property
def _lazy_property(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self)) # Create instance attribute.
return getattr(self, attr_name)
return _lazy_property
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
#lazy_property
def sum(self):
return self.x + self.y
#lazy_property
def sqrtSum(self):
return sqrt(self.sum)
#lazy_property
def SumSquare(self):
return self.sum * self.sum
#lazy_property
def SumCube(self):
return self.sum * self.sum * self.sum
Update
In Python 3.8 a cached_property decorator was added to the functools module which does basically the same thing as lazy_property above, so the code could simply be like this:
from functools import cached_property # Requires Python 3.8+
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
#cached_property
def sum(self):
return self.x + self.y
#cached_property
def sqrtSum(self):
return sqrt(self.sum)
#cached_property
def SumSquare(self):
return self.sum * self.sum
#cached_property
def SumCube(self):
return self.sum * self.sum * self.sum
inst = MyClass(4, 2)
print(inst.sum)
print(inst.SumCube)
Properties are your friends here.
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
#property
def sum(self):
return self.x + self.y
#property
def sqrt_sum(self):
return sqrt(self.sum)
#property
def sum_square(self):
return self.sum * self.sum
#property
def sum_cube(self):
return self.sum * self.sum * self.sum
Thus you could do
user = MyClass(1,2)
print(user.sum) # No parenthesis
print(user.sqrt_sum) # No parenthesis
print(user.sum_square) # No parenthesis
print(user.sum_cube) # No parenthesis
By the way, you should use builtin names (here sum) with caution
You could calculate self.sum directly in __init__ and then you don't have to calculate it again
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
self.sum = self.x + self.y
def compute_sum(self):
return self.sum
def compute_sqrt_sum(self):
return sqrt(self.sum)
def compute_sum_square(self):
#return self.sum * self.sum
return self.sum ** 2
def compute_sum_cube(self):
return self.sum ** 3
user = MyClass(1, 2)
print(user.compute_sqrt_sum())
print(user.compute_sum_square())
print(user.compute_sqrt_cube())
But if you change ie. user.x = 10 then it will use wrong sum.
So it can be good only if you don't want to change x,y,sum.
Eventually in __init__ you can set self.sum = None and calculate sum only when self.sum is None - so it would have to calculate it only once but it would have to always check if self.sum is None:
More or less like this
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
self.sum = None
def compute_sum(self):
if self.sum is None:
self.sum = self.x + self.y
return self.sum
def compute_sqrt_sum(self):
if self.sum is None:
self.compute_sum()
return sqrt(self.sum)
def compute_sum_square(self):
if self.sum is None:
self.compute_sum()
#return self.sum * self.sum
return self.sum ** 2
def compute_sum_cube(self):
if self.sum is None:
self.compute_sum()
return self.sum ** 3
user = MyClass(1, 2)
print(user.compute_sqrt_sum())
print(user.compute_sum_square())
print(user.compute_sqrt_cube())
But if you change ie. user.x = 10 then it will also use wrong sum.
So it can be good only if you don't want to change x,y,sum.
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)
I'm testing some code for a course OOP, but I run into a problem. I am programming a circle and a cylinder, with the circle class also in the init of the cylinder. I have 2 arguments for the cylinder, but when I give 2 arguments, it's said that I only need 1 and if I give one argument than it gaves the output one is missing.
with the variable a it works, but the error is in variable b. What do I wrong
import math
class CCircle:
def __init__(self):
self._radius = 0
#property
def area(self):
return self._radius**2 * math.pi
#area.setter
def area(self, value):
self._radius = math.sqrt(value / math.pi)
#property
def circumference(self):
return self._radius * 2 * math.pi
#circumference.setter
def circumference(self, value):
self._radius = value / (2 * math.pi)
class CCylinder:
def __init__(self, radius, height):
self._circle = CCircle(radius)
self._height = height
#property
def circumference(self):
return self._circle.circumference
#property
def ground_area(self):
return self._circle.area
#property
def total_area(self):
return self._circle.area + self._height * self._circle.circumference
#property
def volume(self):
return self._circle.area * self._height
a = CCircle()
b = CCylinder(1,4)
init() takes 1 positional argument but 2 were given
You should have your CCircle class start like this
class CCircle:
def __init__(self, radius=0):
self._radius = radius
so that you get the default radius of 0 that you seem to want, but can also initialize it with a radius value like you're doing in the init code of your CCylinder class.
The problem is with this line:
self._circle = CCircle(radius)
but __init__ for the CCircle class does not take any arguments (except for self) so this is causing the error.
You might have had a package folder locally at the place where the .py file is , delete that and that should solve your issue
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)
My end goal right now is to take points that are read from a text file, and turn them into 3d objects. They do not need to be visualized, but they need to be stored in objects instead of just a string containing the x, y, and z values. The file gives me six numbers, two of each x, y, and z, and I was wondering how I would go about creating a point class/object that will take all three variables and then a line object/class that will take two of the points.
Just define a Point and a Line class:
class Point(object):
def __init__(self, x=0, y=0 ,z=0):
self.x = x
self.y = y
self.z = z
class Line(object):
def __init__(self, point1=None, point2=None):
self.point1 = point1 or Point() # (0,0,0) by default
self.point2 = point2 or Point() # (0,0,0) by default
To create points and lines objects:
>>> p1 = Point(1, 2, 3)
>>> p2 = Point(4, 5, 6)
>>> line = Line(p1, p2)
Once you have got the data from the file (for this Regular Expressions are applicable), you will want to input that into a class which is defined as to store the two points (which can be objects themselves) e.g.
class Point(tuple):
#property
def x:
return self[0]
#property
def y:
return self[1]
#property
def z:
return self[2]
class Vector(object):
def __init__(self, x1, y1, z1, x2, y2, z2):
self._a = Point(x1, y1, z1)
self._b = Point(x2, y2, z2)
#property
def a(self):
return self._a
#property
def b(self):
return self._b
# Other methods here e.g.
#property
def i(self):
return self.b.x - self.a.x
#property
def j(self):
return self.b.y - self.a.y
#property
def k(self):
return self.b.z - self.a.z
def length(self):
return ( self.i**2 + self.j**2 + self.k**2 ) ** (1/2)