Python property being ignored, acting like an attribute - python

I've got this RoomPlaceholder class with a distance property; when you set the distance property, it should automatically calculate what the x and y of the class should be, based on a random angle and the distance.
class RoomPlaceholder:
def __init__(self, width, height):
self.width = width
self.height = height
self.id = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(8))
self.angle = Util.getRandomAngle() # = random.random() * math.pi * 2
self.distance = 0
#property
def distance(self):
print "gamma"
return self._distance
#distance.setter
def distance(self, value):
print "delta"
self._distance = value
coords = Util.getXYByDist(value, self.angle) # translates angle and distance into integer (x, y)
print coords
self._x = coords[0]
self._y = coords[1]
#property
def x(self):
return self._x
#property
def y(self):
return self._y
def __repr__(self):
return "%s: [%sx%s] # (%s, %s) Distance: %s. Angle: %s." % (self.id, self.width, self.height, self.x, self.y, self.distance, self.angle)
if __name__ == "__main__":
room = RoomPlaceholder(5,5)
print "%s\n" % room.distance
room.distance = 10
print "%s\n" % room.distance
print room
pass
However, it's not working. Based on the output from the console, it looks like it's treating distance as an attribute rather than a property; note that I've got print statements in both the getter ("gamma") and setter ("delta") methods, but we never see either in the output when I get or set the distance:
Traceback (most recent call last):0
File "D:\Dropbox\Programming\Python\DungeonGenerator\NewDungeonGenerator.py", line 142, in <module>
10
print room
File "D:\Dropbox\Programming\Python\DungeonGenerator\NewDungeonGenerator.py", line 132, in __repr__
return "%s: [%sx%s] # (%s, %s) Distance: %s. Angle: %s." % (self.id, self.width, self.height, self.x, self.y, self.distance, self.angle)
File "D:\Dropbox\Programming\Python\DungeonGenerator\NewDungeonGenerator.py", line 97, in x
return self._x
AttributeError: RoomPlaceholder instance has no attribute '_x'
[Finished in 0.0s]
I'm using Python 2.7, and this is being run via Sublime Text 3 in Windows 7.

property only works for new-style classes. You need to make RoomPlaceholder a subclass of object by declaring it thusly:
class RoomPlaceholder(object):
# etc.

Related

Calling method inside __str__ function in python class

'List' object has no attribute 'points' is the error I'm getting. I think I'm not calling points correctly inside the __str__ function, but don't know how to fix it. Before, I had points defined before __str__ and had the same error.
class Persons(object):
def __init__(self,name,radius,home_universe,x,y,dx,dy,current_universe,rewards):
self.name = name
self.radius = radius
self.home_universe = home_universe
self.x = x
self.y = y
self.dx = dx
self.dy = dy
self.current_universe = current_universe
self.rewards = rewards
def __str__(self):
return '{} of {} in universe {}\n at ({},{}) speed ({},{}) with {} rewards and {} points'.\
format(self.name, self.home_universe, self.current_universe, self.x, self.y, self.dx,\
self.dy, len(self.rewards), self.rewards.points())
def points(self):
cnt = 0
if len(self.rewards) == 0:
return 0
else:
for reward in self.rewards:
cnt += reward[2]
return cnt
You use self.rewards.points() but you have only self.points().
Use self.points()

class Rectangle - Python

I'm just beginning working with object-oriented programming. I have created some classes and am trying to complete the rectangle class. Any and all help is appreciated.
I'm confused about when you need to refer to self and when you can just create variables. For example, in defining the length of the rectangle, I don't know if I should call the variable self.length or just length, and I haven't been able to find any rectangle classes defined in this way.
import math
class Point (object):
# constructor
def __init__ (self, x = 0, y = 0):
self.x = x
self.y = y
# get distance
def dist (self, other):
return math.hypot (self.x - other.x, self.y - other.y)
# get a string representation of a Point object
def __str__ (self):
return '(' + str(self.x) + ", " + str(self.y) + ")"
# test for equality
def __eq__ (self, other):
tol = 1.0e-16
return ((abs (self.x - other.x) < tol) and (abs(self.y - other.y) < tol))
class Circle (object):
# constructor
def __init__ (self, radius = 1, x = 0, y = 0):
self.radius = radius
self.center = Point (x, y)
# compute cirumference
def circumference (self):
return 2.0 * math.pi * self.radius
# compute area
def area (self):
return math.pi * self.radius * self.radius
# determine if point is strictly inside circle
def point_inside (self, p):
return (self.center.dist(p) < self.radius)
# determine if a circle is strictly inside this circle
def circle_inside (self, c):
distance = self.center.dist (c.center)
return (distance + c.radius) < self.radius
# determine if a circle c intersects this circle (non-zero area of overlap)
def does_intersect (self, c):
# string representation of a circle
def __str__ (self):
# test for equality of radius
def __eq__ (self, other):
tol = 1.0e-16
class Rectangle (object):
# constructor
def __init__ (self, ul_x = 0, ul_y = 1, lr_x = 1, lr_y = 0):
if ((ul_x < lr_x) and (ul_y > lr_y)):
self.ul = Point (ul_x, ul_y)
self.lr = Point (lr_x, lr_y)
else:
self.ul = Point (0, 1)
self.lr = Point (1, 0)
# determine length of Rectangle
def length (self):
# determine width of Rectangle
def width (self):
# determine the perimeter
def perimeter (self):
# determine the area
def area (self):
# determine if a point is strictly inside the Rectangle
def point_inside (self, p)
# determine if another Rectangle is inside this Rectangle
def rectangle_inside (self, r):
# determine if two Rectangles overlap
def does_intersect (self, other):
# determine the smallest rectangle that circumscribes a circle
def rect_circumscribe (self, c):
# give string representation of a rectangle
def __str__ (self):
# determine if two rectangles have the same length and width
def __eq__ (self, other):
Basically, setting a value to self.length gives you the ability to access this value from other functions inside the class and from outside of the class. If you set a value to length, you are able to access this variable only in the current function inside the class.
Just a start, try to continue yourself:
class Rectangle (object):
# constructor
def __init__ (self, ul_x = 0, ul_y = 1, lr_x = 1, lr_y = 0):
# Called if you say: my_rectancle = Rectangle (-10, 10, 10, -10)
# Puts parameters in fields of your newly created object of class Rectancle
self.ul_x = ul_x
self.ul_y = ul_y
self.lr_x = lr_x
self.lr_y = lr_y
# compute cirumference
def circumference (self):
return 2 * (self.ur_x - self.lr_x) + 2 * (self.ul_y - self.lr_y)
# compute area
def area (self):
return (self.ur_x - self.lr_x) * (self.ul_y - self.lr_y)
[EDIT]
With regard to the additional code in your comment, it's quite close to what it should be. With some corrections:
# determine length of Rectangle
def length (self):
return self.ul_y - self.lr_y
# determine width of Rectangle
def width (self):
return self.lr_x - self.ul_x
# self. has been added, since e.g. lr_x is not a parameter
# of the width function, but a field of the object you make
# by instantiation: 'rectangle = Rectangle (10, 20, 100, 200)'
# After that, self refers to the object 'rectangle' you created,
# which has class 'Rectangle'.
#
# Note that a class is a type.
# You can have a type 'Dog'.
# Dog 'fluffy' is an instance of that class, so a particular dog.
# In the methods (functions) of 'Dog', 'self' refers to the particular
# dog you're working with.
# determine the perimeter
def perimeter (self):
return 2 * self.width () + 2 * self.length ()
# Note the () after width and length.
# They're needed because width and length are
# function calls (they DO something) rather than fields (data)
# You could also have stored width and length into fields,
# just like the constructor did with ul_x, ul_y, lr_x and lr_y,
# storing them in self.ul_x, self.ul_y etc.
# Then the braces wouldn't have been needed.
# But also out some superfluous braces here
# Multiplication goes before addition anyhow
# And return returns everything after it, no braces needed.
# determine the area
def area (self):
return self.width () * self.length ()
So, how far did you get now?

Python - point class not getting correct output

So I have a point class and a line class that both have a scale method.
class Point:
def __init__(self, x, y):
if not isinstance(x, float):
raise Error("Parameter \"x\" illegal.")
self.x = x
if not isinstance(y, float):
raise Error ("Parameter \"y\" illegal.")
self.y = y
def scale(self, f):
if not isinstance(f, float):
raise Error("Parameter \"f\" illegal.")
self.x = f * self.x
self.y = f * self.y
def __str__(self):
return '%d %d' % (int(round(self.x)), int(round(self.y)))
class Line:
def __init__(self, point0, point1):
self.point0 = point0
self.point1 = point1
def scale(self, factor):
if not isinstance(factor, float):
raise Error("Parameter \"factor\" illegal.")
self.point0.scale(factor)
self.point1.scale(factor)
def __str__(self):
return "%s %s" % (self.point0, self.point1)
So one of the tests I do on this code is to check for a shallow copy which I do in this test code.
p0.scale(2.0)
p1.scale(2.0)
print line
The problem is the print line gives me 0 2 4 6 and it should give me 0 1 2 3. So why is it printing multiples of 2 instead? The scale method is supposed to return the scaled values and for all the other test cases it prints the expected values however just with this test code it prints values I didn't expect. Here's how the values of p0 and p1 are set up:
print '********** Line'
print '*** constructor'
p0 = Point(0.0, 1.0)
p1 = Point(2.0, 3.0)
line = Line(p0,p1)
print line
In your __init__ method for Line, you are assigning the names self.point0 and self.point1 to the two points that are passed in. This does not make a new copy, only gives the objects in memory another name. If you change this method to
def __init__(self, point0, point1):
self.point0 = Point(point0.x, point0.y)
self.point1 = Point(point1.x, point1.y)
then everything should work as intended. Or, you can use the copy module:
from copy import copy
class Line:
def __init__(self, point0, point1):
self.point0 = copy(point0)
self.point1 = copy(point1)
You could also define your own __copy__ and __deepcopy__ methods on your Point class.
def __copy__(self):
return type(self)(self.x, self.y)
def __deepcopy__(self, memo):
return type(self)(self.x, self.y)
You can look at this question for more information.
Printing line after scaling p0,p1 by 2 multiply x,y pairs for p0, p1. Line instance values of point0 and point1 pointing to instances of Point which is p0 and p1 appropriately, as result of print line you can see updated value of x,y of each point.
p0 = Point(0,1)
p1 = Point(2,3)
line = Line(p0, p1)
print line # 0 1 2 3
p0.scale(2.0)
p1.scale(2.0)
print line # 0 2 4 6

Construct object (Rectangle) without arguments when __init__ of class requires parameters

I am working on an assignment that requires a Rectangle class that computes the area and perimeters given. We are given the main() function already and have to build around it. It seems to run up until it gets to b = Rectangle() where it says it
requires exactly 3 arguments.
Here is my code:
class Shape(object):
def __init__(self):
pass
def area():
pass
def perimeter():
pass
class Rectangle(Shape):
def __init__(self, width, height):
Shape.__init__(self)
self.width = width
self.height = height
def area(self):
area = self.height * self.width
return area
def perimeter(self):
perimeter = 2*(self.width+self.height)
return perimeter
def getStats():
print "Width: %d" % b.width
print "Height: %d" % b.height
print "Area: %d" % b.area
print "Perimeter: %d" % b.perimeter
def main():
print "Rectangle a:"
a = Rectangle(5, 7)
print "area: %d" % a.area()
print "perimeter: %d" % a.perimeter()
print ""
print "Rectangle b:"
b = Rectangle()
b.width = 10
b.height = 20
print b.getStats()
main()
How to get the second rectangle to work without changing the main function?
Read on python's support for default arguments for "constructors"... Something like
def __init__(self, width = 0, height = 0)

Add method that works with either a Point Object or a tuple

One of my exercises says to write an add method for Points that works with either a Point object or a tuple:
If the second operand is a Point, the method should return a new Point whose x coordinate is the sum of the x coordinates of the operands, and likewise for the y coordinates.
If the second operand is a tuple, the method should add the first element of the tuple to the x coordinate and the second element to the y coordinate, and return a new Point with the result.
This how far I got and I'm not sure if the tuple portion of my code is accurate. Can someone shed some light how I would call this program for the tuple portion. I think I nailed the first part.
Here is my code:
Class Point():
def__add__(self,other):
if isinstance(other,Point):
return self.add_point(other)
else:
return self.print_point(other)
def add_point(self,other):
totalx = self.x + other.x
totaly = self.y + other.y
total = ('%d, %d') % (totalx, totaly)
return total
def print_point(self):
print ('%d, %d) % (self.x, self.y)
blank = Point()
blank.x = 3
blank.y = 5
blank1 = Point()
blank1.x = 5
blank1.y = 6
That's what I've built so far and I'm not sure how to actually run this with the tuple part. I know if it did blank + blank1 the if portion would run and call the add_point function but how do I initiate the tuple. I'm not sure if I wrote this correctly... please assist.
You can simply derive your class from the tuple (or just implement __getitem__).
class Point(tuple):
def __new__(cls, x, y):
return tuple.__new__(cls, (x, y))
def __add__(self, other):
return Point(self[0] + other[0], self[1] + other[1])
def __repr__(self):
return 'Point({0}, {1})'.format(self[0], self[1])
p = Point(1, 1)
print p + Point(5, 5) # Point(6, 6)
print p + (5, 5) # Point(6, 6)
Alternatively, if you want to be able to use point.x and point.y syntax, you could implement the following:
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
if isinstance(other, Point):
return Point(self.x + other.x, self.y + other.y)
elif isinstance(other, tuple):
return Point(self.x + other[0], self.y + other[1])
else:
raise TypeError("unsupported operand type(s) for +: 'Point' and '{0}'".format(type(other)))
def __repr__(self):
return u'Point ({0}, {1})'.format(self.x, self.y) #Remove the u if you're using Python 3

Categories

Resources