I have a class with instance variables which I want to modify in a loop using a class method, simplified version of what I'm doing:
class Example:
def __init__(self,x,z):
self.x=x
self.z=z
def run(self,y):
temp_list=[self.x, self.z]
for ind,item in enumerate(temp_list):
temp_list[ind] = temp_list[ind]+y
print (self.x, self.z)
ex = Example(5,6)
ex.run(5)
The output I get is [5,6] instead of the desired [10,11].
I was wondering if anyone could point me to an explanation as to why this happens?
In run(), you create a list of 2 items, the value self.x and self.z. Next, you iterate over that list, and modify each value by adding y to it.
After the for-loop, temp_list will be [10, 11], but you have not modified self.x or self.y in any way.
Hence, the print() call will print the unmodified self.x and self.y values, being 5 and 6 in your example.
If you don't actually write self.x = ..., then you can generally assume that self.x will not be modified. When you write temp_list[ind] + y and store it in temp_list[ind], you're updating the list with a new value, which has no bearing on any values that other variables happen to hold (including your object's x variable).
To get the desired result with code similar to yours, you could do something like this:
class Example:
def __init__(self,x,z):
self.list=[x, z]
def run(self,y):
for ind,item in enumerate(self.list):
self.list[ind] = self.list[ind]+y
print (self.list)
ex = Example(5,6)
ex.run(5)
This would create a self.list item in your init definition that would then be used to iterate over the initial values and add your y value to it. The main error you had was printing an unaltered list (but you were on the right track!)
Hope this helps!
You can use, the example under.
class Example:
def __init__(self, x, z):
self.x = x
self.z = z
def run(self,y):
# Put your init arguments into the array
result = [self.x, self.z]
# Modify your init arguments
for x in range(len(result)):
result[x] += y
# Return the array with new values
return result
ex = Example(5, 6)
print(ex.run(5))
Maybe the link would be helpful for you, learn for loop in python
Related
I have a "Node" class which takes as arguments x and y. The class methods calculate different values. I have multiple instances of this class called "nodes". What I want is to find the node with the lowest "fcost" and get the x and y coordinates of that node.
I have no idea how to solve this problem so it would be much appreciated if you could help me.
class Node():
# Node class
def __init__(self, y, x):
self.y = y
self.x = x
def gcost(self):
return self.x + self.y
def hcost(self):
return self.x * self.y
def fcost(self):
return self.gcost() + self.hcost() # method that indicates
# which node to choose
node1 = Node(5,5)
node2 = Node(2,2)
nodes = [node1, node2] # I actually don't know if I should create a
# list of nodes so please tell me if I should
# not
### CODE TO SOLVE THE PROBLEM ###
In this case the lowest fcost between node1 and node2 is node2's fcost so I expect the output to be:
(2,2) or [2,2]
Either a list or a tuple, either way is fine.
You should use the min() function. You can use it in different ways, but in this scenario, I think that the simplest solution would be to use a lambda function - which is a shorter way to write and define functions in python.
You can read more about the min() function here, and more about lambda functions here.
Anyway, this piece of code should work just fine:
class Node():
# Node class
def __init__(self, y, x):
self.y = y
self.x = x
def gcost(self):
return self.x + self.y
def hcost(self):
return self.x * self.y
def fcost(self):
return self.gcost() + self.hcost()
node1 = Node(5,5)
node2 = Node(2,2)
nodes = [node1, node2]
needed_node = min(nodes, key=lambda x:x.fcost())
needed_list = [needed_node.x, needed_node.y] # in case you want the result as a list
needed_tuple = (needed_node.x, needed_node.y) # in case you want the result as a tuple
Use min(list, key=...).
min_node = min(nodes, key=lambda n:n.fcost())
print(min_node, min_node.fcost(), min_node.x, min_node.y)
key has to be name of function.
min will use it to get value which it will compare to find minimal one.
Is there any way to find an object saved in a list, knowing only its parameters and without traversing the said list?
For example, there's a class, objects of which have an (x;y) coordinate, and none of the objects share the same coordinate (all x/y pairs are distinct and do not repeat). These objects are all saved in a list:
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
points = [Point(...), Point(...), Point(...), Point(...), ...]
Whenever I need the specific instance, is there any way to find it (here: its index in the list) by using just its coordinates without traversing the whole list like here:
def find_objects_index(x, y):
for i in range(len(points)):
if points[i].x == x and points[i].y == y:
return i
EDIT: these Point()s are to be accessed for writing, not reading, and so object.x and object.y will be changing, you can't just create a dictionary with (object.x, object.y) as keys - you'd need to add a new entry and delete the old one each time.
You can use list aggregation with a condition to get the item(s) you are looking for:
matching = [p for p in points if p.x = VALX and p.y == VALX]
However, in this case having a dictionary with (x, y) as key is most likely the correct (and well performing) way to go.
Is there any way to find an object saved in a list, knowing only its
parameters and without traversing the said list?
Short answer: No.
If you want or need to traverse such a collection of data points rapidly, perhaps you should consider using an type other than a list--a binary tree based off x or y data, for example (or if you need to track them separately, perhaps one tree for each)?
Just put the Points in a dict():
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
points_list = [Point(...), Point(...), Point(...), Point(...), ...]
points_dict = {(p.x,p.y):p for p in points_list}
def find_object(x, y):
if (x,y) in points_dict:
return points_dict[(x,y)]
def replace_object(x, y, new_point):
points_dict.pop((x, y), None)
points_dict[(new_point.x, new_point.y)] = new_point
I am trying to sort the Points based on the X and Y properties of the point object.A small example below to explain my process:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return '[{},{},{}]'.format(self.x, self.y, self.z)
#point instances
p1,p2,p3 = Point(7,85,5), Point(56,16,20), Point(24,3,30)
point_list = [p1,p2,p3]
def get_X(point):
return point.x
def get_Y(point):
return point.y
sorted_points = sorted(point_list, key = get_X)
# print(sorted_points) // [[7,85,5], [24,3,30], [56,16,20]]
sorted_points = sorted(sorted(point_list, key = get_X), key = get_Y)
# print(sorted_points) // [[24,3,30], [56,16,20], [7,85,5]]
But I need an output like this sorting X first keep them in same order and then sort Y
[[7,3,5], [24,16,30], [56,85,20]]
I think I am trying to exchange the properties of each instances by achieving the above, But I don't know how to do that.
Tuples will naturally sort in the way you want. You can simplify things by adding a __lt__() function to your class. Sorted will use this function to compare. Then you can depend on the natural sorting order of tuples easily with something like this:
class Point:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
return '[{},{},{}]'.format(self.x, self.y, self.z)
def __iter__(self):
return iter((self.x, self.y, self.z))
def __lt__(self, other):
return (self.x, self.y, self.z) < (other.x, other.y, other.z)
#point instances
point_list = [Point(7,85,5), Point(56,16,20), Point(24,3,30), Point(7, 20, 0), Point(56,16,15)]
sorted(point_list)
# --> [[7,20,0], [7,85,5], [24,3,30], [56,16,15], [56,16,20]]
EDIT: Create new points
To create new points by combining the sorted elements of each point individually you can unzip your points, sort them and then zip them again. The nicest way to do this is to add an __iter__() function to your class to make it iterable so it can support zip. I've done this in the code above. This will allow you to do this:
point_list = [Point(7,85,5), Point(56,16,20), Point(24,3,30), Point(7, 20, 0), Point(56,16,15)]
newTuples = list(zip(*[sorted(l) for l in zip(*point_list)]))
sortedPoints = [Point(*p) for p in newTuples ]
#sortedPoint => [[7,3,0], [7,16,5], [24,16,15], [56,20,20], [56,85,30]]
This also sorts the z values, but it's easy enough to change that if you need it for some reason.
By placing the key elements in tuples in the order you want them sorted (primary value first, secondary value second), the ordering method of tuples will automatically perform in the way you are hoping to achieve.
All you need to change is that your value for key should be set to key=get_XY, where get_XY returns a tuple of x and y coordinates:
def get_XY(point):
return point.x, point.y
I have a list of vectors
vector1=[1,1]
vector2=[2,2]
favoritevector=[1,-1]
Then a list of those vectors
vectors=[]
vectors.append(vector1)
vectors.append(vector2)
vectors.append(favoritevector)
vector
>>vector = [[1,1], [2,2], [1,-1]]
How can I retrieve the names of the objects inside the list vectors, instead of the actual value of the objects.
In this case, I would like to something that if I ask for the element 0 of the list vectors the function or command returns to me the name "vector1" instead of [1,-1].
Thanks in advance for the help.
I don't think there is a way to do this using a list. You might try something like this:
class vector(object):
def __init__(self, name, x, y):
self.name = name
self.x = x
self.y = y
def __repr__(self):
return """<vector {} {}>""".format(self.name, (self.x, self.y))
Then, you can do:
vectors = []
vectors.append(vector(name="vector1", x=1, y=2))
vectors.append(vector(name="vector2", x=2, y=3))
# to get the name of the first vector, do:
vectors[0].name
# 'vector1'
If the order of the vectors is not important you can use dictionaries
vectors_dict["vector1"] = [1, 1]
I was just wondering when to store things as part of a class instance versus when to use a method to return things. For example, which of the following would be better:
class MClass():
def __init__(self):
self.x = self.get_x()
self.get_y()
self.z = None
self.get_z()
def get_x(self):
return 2
def get_y(self):
self.y = 5 * self.x
def get_z(self):
return self.get_x() * self.x
What are the conventions regarding this sort of thing and when should I assign things to self and when should I return values? Is this essentially a public/private sort of distinction?
You shouldn't return anything from __init__.
Python is not Java. You don't need to include get for everything.
If x is always 2 and y is always 10 and z is always 12, that is a lot of code.
Making some assumptions, I would write that class:
class MClass(object):
def __init__(self, x):
self.x = x
def y(self):
return self.x * 5
def z(self):
return self.x + self.y()
>>> c = MClass(2)
>>> c.x
2
>>> c.y() # note parentheses
10
>>> c.z()
12
This allows x to change later (e.g. c.x = 4) and still give the correct values for y and z.
You can use the #property decorator:
class MClass():
def __init__(self):
self.x = 2
#property
def y(self):
return 5 * self.x
#here a plus method for the setter
#y.setter
def y(self,value):
self.x = y/5
#property
def z(self):
return self.x * self.x
It's a good way of organizing yours acessors
There's no "conventions" regarding this, AFAIK, although there're common practices, different from one language to the next.
In python, the general belief is that "everything is public", and there's no reason at all to have a getter method just to return the value of a instance variable. You may, however, need such a method if you need to perform operations on the instance when such variable is accessed.
Your get_y method, for example, only makes sense if you need to recalculate the expression (5 * self.x) every time you access the value. Otherwise, you should simply define the y variable in the instance in __init__ - it's faster (because you don't recalculate the value every time) and it makes your intentions clear (because anyone looking at your code will immediately know that the value does not change)
Finally, some people prefer using properties instead of writing bare get/set methods. There's more info in this question
I read your question as a general Object Oriented development question, rather than a python specific one. As such, the general rule of member data would be to save the data as a member of the class only if it's relevant as part of a particular instance.
As an example, if you have a Screen object which has two dimensions, height and width. Those two should be stored as members. The area associated with a particular instance would return the value associated with a particular instance's height and width.
If there are certain things that seem like they should be calculated on the fly, but might be called over and over again, you can cache them as members as well, but that's really something you should do after you determine that it is a valid trade off (extra member in exchange for faster run time).
get should always do what it says. get_y() and get_z() don't do that.
Better do:
class MClass(object):
def __init__(self):
self.x = 2
#property
def y(self):
return 5 * self.x
#property
def z(self):
return self.x * self.x
This makes y and z always depend on the value of x.
You can do
c = MClass()
print c.y, c.z # 10, 4
c.x = 20
print c.y, c.z # 100, 400