Totally rewritten code:
HOR = [0, 1, 3, 6]
VER = [0,10,20,100,1000]
class Pos:
def __init__(self, x, y):
if (x in HOR) and (y in VER):
self.x = x
self.y = y
else:
print "Invalid position: ", x, y
def __str__(self):
return self.x + self.y
def get_x(self):
return self.x
def get_y(self):
return self.y
class list_A1:
def __init__(self): # create a A1 object
self.list_A1 = []
for i in HOR:
for j in VER:
self.list_A1.append(Pos(i,j))
def __str__(self):
d = "list_A1 contains: " + repr(self)
return d # return a string representing the A1
a1 = list_A1()
print a1
Now I get:
list_A1 contains: <__main__.list_A1 object>
but I want to get list of [x,y], for example:
[[1,1],[1,2]...]
I am new to object programming and I don't understand why I can't see these values in the list.
The parentheses after self.A1 mean that you are trying to call it as if it were a function. As the error message tells you, you cannot call a list. The correct syntax would be:
d = "A1 contains: " + str(self.A1)
or, better
d = "A1 contains: {}".format(self.A1)
Also, you seem to be using A1 (the class name) and A (the instance attribute) interchangeably; you should give your classes, attributes and methods more sensible and meaningful names to help avoid this issue.
Do
self.A.append(Pos(x,y))
instead of
self.A1.append(Pos(x,y))
and
d = "A1 contains: " + str(self.A)
Edit:
Implement str(self) and repr(self) of Pos if you want to print them.
A1.A1 is not defined in your code example. If it is a list, just change the line to:
d = "A1 contains: " + str(self.A1)
Related
I am trying to create a simple class for n-dimensional vectors, but I cannot figure out how to add 2 vectors with n arguments together. I cannot find a way to return a variable amount of arguments in the __add__ function. In specific dimensions, this isn't too hard. Here's what it would look like for 2 dimensions:
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return '({:g} , {:g} )'.format(self.x, self.y)
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
v, w = Vector2D(1,2), Vector2D(1,1)
print(v+w) #this should return (2, 3 )
Now I'd like to generalize this class to include all dimensions. I would probably use *args instead of x and y. Here's what that would sort of look like:
class Vector:
def __init__(self, *args):
self.args = args
def __str__(self):#not terribly important, but this function is quite ugly
string = '( '
for i in self.args:
string += str(i)
string += ', '
string += ')'
return string
def __add__(self, other): #how would one do this?
pass
v, w = Vector(2,3,4), Vector(1,1,1)
print(v+w) #I want this to return (3, 4, 5, )
I came up with some sort of solution, but it's not terribly efficient. Instead of loose argument, this version of my class uses a single list. I find this unsatisfactory however, so I came here to ask for a better solution. I have shared my mediocre solution down below:
class Vector:
def __init__(self, list = []):
self.list = list
def __str__(self):
string = '('
for i in self.list:
string += str(i)
string += ', '
string += ')'
return string
def __add__(self, other):
if len(self.list) == len(other.list):
coordinates = []
dimension = len(self.list)
for i in range(dimension):
newcoordinate = self.list[i] + other.list[i]
coordinates.append(newcoordinate)
return Vector(coordinates)
else:
raise TypeError('Can only add vectors of the same dimension.')
v, w = Vector([2,3,4]), Vector([1,1,1])
print(v+w) #this should return (3, 4, 5, )
In summary, I don't want to have to put the coordinates of a vector in a list. I can't think of a way to implement an __add__ function though.
Let's assume we have some classes defined and available in global namespace. In example:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Vector:
def __init__(self, alpha, r):
self.x = r * cos(alpha)
self.y = r * sin(alpha)
# and many others...
How to do this:
class_name = 'Point'
x = 14.361
y = -8.100
code_str = 'class_object = ' + class_name + '(' + str(x) + ', ' + str(y) + ')'
exec code_str # That evaluates to: "class_object = Point(14.361, -8.100)"
print class_object.x, class_object.y
without using the dangerous exec?
PS. I'm intending to load the data from some txt or json file if anyone asks.
If the class is defined or imported in the same module, you could use something like :
globals()[class_name](x, y)
if you have many classes to handle, you should better use a dictionnary to store them, key is the name, value is the class,
then you can call it with :
my_classes = {'Point' : Point, 'Point2' : Point2}
class_name = 'Point'
x = 14.361
y = -8.100
my_classes[class_name](x, y)
Provided that a class is defined in (or imported into) the global namespace, you can get a reference to it via the dictionary returned by globals(). After that just create an instance the usual way, e.g.:
class_name = 'Point'
kwargs = {'x': 14.361, 'y': -8.100}
Point = globals()[class_name]
point = Point(**kwargs)
You can use eval.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Vector:
def __init__(self, x, y):
self.x = x+100
self.y = y+100
class_name = 'Vector'
x = 10
y = 20
caller = '{}({},{})'.format(class_name,x,y)
ob = eval(caller)
print ob.x, ob.y
I am developing a module that draws lines and finds their midpoints. For purposes of testing, I want to create some string outputs from the relevant classes.
class Line:
def __init__(self, endpoints):
self.start = endpoints[0]
self.end = endpoints[1]
def midpoint():
x = (start.getX + end.getX) / 2.0
y = (start.getY + end.getY) / 2.0
return Point(x, y)
def __str__(self):
return "line from " + `self.start` + " to " + `self.end` + "."
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def getX():
return x
def getY():
return y
def __str__(self):
return "[" + str(self.x) + ", " + str(self.y) + "]"
__repr__ = __str__
point1 = Point(4,5)
point2 = Point(0,0)
line1 = Line([point1, point2])
print line1
print line1.midpoint
Expected output:
line from [4, 5] to [0, 0]
[2.0, 2.5]
Instead I get:
line from [4, 5] to [0, 0]
<bound method Line.midpoint of <__main__.Line instance of 0x105064e18>>
How can I get the expected string representation of the midpoint, which is being returned as an instance of the Point class?
You are printing the method itself, not the returned value of the method. Change your last line to this:
print line1.midpoint()
Also, the first definition line of your method should use self as the only parameter, like so:
def midpoint(self):
The same applies to the rest of the methods, they should have self as a parameter (Point.getX and Point.getY).
In the midpoint method, you should have start.getX(), start.getY(), end.getX(), and end.getY() should have "self." in front of it. You should also have "self" as a parameter for the method for every method in a class.
midpoint method
I will paste the entire code below to show you exactly what I have done.
entire code
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
Below is a code which I am working with. My program creates combination of possible positions and gets the last position. Then I want to get the value for that position based on the letter from list A and a dictionary dictionary VALUES. When I execute this code I get:
AttributeError: 'Combination' object has no attribute 'get_value'
X = ['A','B','C']
Y = ['1','2','3']
VALUES_FOR_X = {'A':1, 'B': 2, 'C':3}
class Combination: # Creates a list of possible position combinations
def __init__(self,x,y):
if (x in X) and (y in Y):
self.x = x
self.y = y
else:
print "WRONG!!"
def __repr__ (self):
return self.x+self.y
class Position: # Makes operation on the chosen position
def __init__(self):
self.xy = []
for i in X:
for j in Y:
self.xy.append(Combination(i,j))
def choose_last(self):
return self.xy.pop()
def get_value(self):
return self.VALUES_FOR_X()
def __str__(self):
return "List contains: " + str(self.xy)
pos = Position()
print pos
last_item = pos.choose_last()
print "Last item is:", last_item
print last_item.get_value()
Does anyone knows how to change this code in the simplest way to make it working?
The logic of this program:
We have possible X,Y positions. We create all possible combinations. Then we chose the last position from possible combinations, eg.: C3
Untill here program works perfectly
Now I want to get values of position C3. Using dictionary value for 'C' in C3 is 3. And I want to print this value (3).
To do this I added method:
def get_value(self):
return self.VALUES_FOR_X()
If I understand you Problem correctly this is the Solution:
X = ['A','B','C']
Y = ['1','2','3']
VALUES_FOR_X = {'A':1, 'B': 2, 'C':3}
class Combination: # Creates a list of possible position combinations
def __init__(self,x,y):
if (x in X) and (y in Y):
self.x = x
self.y = y
else:
print "WRONG!!"
def get_value(self):
return VALUES_FOR_X[self.x]
def __repr__ (self):
return self.x+self.y
class Position: # Makes operation on the chosen position
def __init__(self):
self.xy = []
for i in X:
for j in Y:
self.xy.append(Combination(i,j))
def choose_last(self):
return self.xy.pop()
def __str__(self):
return "List contains: " + str(self.xy)
pos = Position()
print pos
last_item = pos.choose_last()
print "Last item is:", last_item
print last_item.get_value()
My output is:
>>> List contains: [A1, A2, A3, B1, B2, B3, C1, C2, C3]
>>> Last item is: C3
>>> 3