What happens in this class? - python

I am trying to alter a program, but i first need to fully understand the code.
class Coordinate:
def __init__(self,x,y):
self.x = x
self.y = y
def equal_to(self,coordinate):
return coordinate.x == self.x and coordinate.y == self.y
def merge_together(self,coordinate_together):
return Coordinate(self.x+coordinate_together.x,self.y+coordinate_together.y)
What is the functionality of this class?
I can't understand -- especially the return coordinate.x and coordinate.y parts.

::merge_together sums (Euclidean translation) the ordinates, returning a new Coordinate instance.
::equal_to compares two Coordinate objects (but perhaps should be using the __eq__ idiom -- along with related methods).

it returns True if coordinate.x == self.x AND coordinate.y == self.y.
(looks like same position)
The method expects and instance of Coordinate probably (see below the same object)

Related

Check if an object is in a set (Python)

Let say I have the following Point Class.
class POINT:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
Main function:
def main():
mySet = set()
a = POINT(1,2)
mySet.add(a)
b = POINT(1,2)
print("B is in mySet= {}".format(b in mySet))
I would like to know an efficient way to check if an object(a point) is in a set.
I know two ways to accomplish it, but they are either not efficient or don't use a custom object:
Traverse through all the point objects in the set --> O(n)
Use set to represent points. i.e (1,2) in mySet --> not using a custom object
I believe when using the key term in, it will check the id or hash values of objects. I wonder what key term allows me to check the values of objects in a set.
We could rephrase this question to "how to use in key term with a custom object?"
We need to define hash in the custom class. How do we do it?
We need to consider two main cases:
Avoid collision
Efficient
We could get collision if we define hash = self.x + self.y because Point(x,y) and Point(y,x) would give the same hash values and it shouldn't be since their x's and y's are not the same.
One way to avoid it is by using a built-in hash function that takes objects. We could convert our self.x and self.y to a tuple object so that it can be used with the hash function. The efficient of this would be depend on how Python implements the hash().
class POINT:
def __hash__(self):
return hash((self.x, self.y))

Vector multiplication python

Hello im learning python and i get class topic.
I recived a error message like this:
"TypeError: __init__() missing 1 required positional argument: 'y'"
this is my code from shell:
class Vektor():
""" Bu bir vektör sınıfıdır"""
def __init__(self,x,y):
self.x = x
self.y = y
def boyu(self):
boy = (self.x**2+self.y**2)**0.5
return boy
def __repr__(self):
return ("%di + %dy" %(self.x, self.y))
def __sub__(self,digeri):
return Vektor(self.x - digeri.x, self.y - digeri.y)
def __add__(self,digeri):
return Vektor(self.x + digeri.x, self.y + digeri.y)
def __eq__(self,digeri):
if self.boyu() == digeri.boyu(): return True
def __mul__(self,digeri):
self.x = Vektor(self.x + digeri.x)
self.y = Vektor(self.y + digeri.y)
return Vektor(self.x*digeri.x,self.y*digeri.y)
When i try to create a C = A*B like this i get error:
TypeError: init() missing 1 required positional argument: 'y'
Im already thank you and i want to remind im a newbite in programming :))
How many arguments does Vektor.__init__ require? Ignoring self, it's two - x and y.
When you wrote return Vektor(self.x*digeri.x,self.y*digeri.y), you passed two arguments, so this works.
When you wrote self.x = Vektor(self.x + digeri.x), this doesn't work, because you don't pass a second argument for the y value.
When Python gave you the error, it should have included a line number, which is supposed to show where the error occurred. You didn't include that, but it was this line, wasn't it?
Since Vektor is supposed to contain two scalars and not sometimes replace them with two vectors, you could just write
self.x = self.x + digeri.x # still not a vector
self.y = self.y + digeri.y # also not a vector
but the more important lesson is to read the error message carefully. Everything you needed was there.
A note on operator semantics: since you wouldn't normally expect an expression like x = v * w to modify x, you shouldn't be mutating self inside the operator function anyway.
You return the resultant vector, which is enough. I showed you how to fix the syntax of those two lines, but you should really just remove them entirely.
And another note on vectors: overloading * isn't such an obvious win as it is for a scalar numeric type, because vectors usually have more than one possible type of product.
In __mul__ you do for some reason:
self.x = Vektor(self.x + digeri.x)
which is calling Vektor.__init__ providing only the positional argument x, with the value self.x + digeri.x, but nothing for y, thus the error.
Also this attempts to change the attribute x into an object from Vektor itself, I can't imagine that this is somehow what you want.
To me it is not clear what the 2 lines before the return statement in your __mul__ are supposed to do. Also both lines will produce the error you see.
Should your __mul__ be the dot product? If so, try:
return self.x*digeri.x + self.y*digeri.y
Another simplification to your class could be to allow iteration on your coords, like:
#property
def coords(self):
return self.x, self.y
def __iter__(self):
return self.coords.__iter__()
Then your dot product might just look like:
def dot(self, w):
"""
The dot product of self and other vector w.
"""
return sum([xi_s * xi_w for xi_s, xi_w in zip(self, w)])
There is VecPy, a very simple example class that does this kind of things. Maybe having a look can give you some more ideas.
The error is due to
self.x = Vektor(self.x + digeri.x)
When we call Vector like the way you write the syntax, it is thinking that you want to initialize it and it is expecting two inputs. Just get rid of the first two lines of mul function should fix the problem.

From Point class to Linestring class

I have created a Point class that takes x,y coords as arguments. Also I wanted to create a Linestring class that takes as many arguments as the user wants and store them as points. So far :
class Point(object):
def __init__(self,x,y):
self.x = x
self.y = y
def move(self,movex,movey):
self.x += movex
self.y += movey
class LineString(object):
def __init__(self, *args):
self.points = [Point(*p) for p in args]
So now I have stored in self.points a list of points.
The questions is how can I use the move function of points, in the class linestring.
I tried something like that but it does not work
def moveline(self,movex,movey):
self.points.move(movex,movey)
To spell out exactly what #MichaelButscher stated in the comments, the issue with your moveline function is that self.points is a list of Point objects rather than a Point object itself. Therefore, we need to iterate through this list and call the move function for each of these Point objects. This can be accomplished with a for loop. Your updated moveline function could look like this:
def moveline(self,movex,movey):
for point in self.points:
point.move(movex,movey)

When to store things as part of an instance vs returning them?

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

Two objects in a method from a class?

I'm having a small issue with this code, I am currently learning about classes and trying to separate the two objects I have created to use both of them in a method from the class.
import math
class Segment:
def __init__(self, xcoord = 0, ycoord = 0):
self.x = xcoord
self.y = ycoord
def get(self):
return (self.x, self.y)
def setx(self, xcoord):
self.x = xcoord
def sety(self, ycoord):
self.y = ycoord
def length(self, xcoord, ycoord):
return math.sqrt(math.pow(xcoord-ycoord,2)+(xcoord-ycoord,2))
p1 = Segment(3,4)
p2 = Segment()
p2.setx(5)
p2.sety(5)
s = Segment(p1,p2)
print(Segment.get(p1))
print(Segment.get(p2))
print(s.length())
I know that I am missing parameters in my length() method, or perhaps I have not? I would like to understand how I am able to have the objects interact with on another after I have defined them.
For further clarity, I am trying to print the distance between the two objects using the parameters I have assigned to them.
Okay, let's forget the code for a second. Firstly, let's talk about naming things. Your Segment class is not a class of segments - it's a class of points. So let's start by renaming your class Point.
class Point:
def __init__(self, xcoord = 0, ycoord = 0):
self.x = xcoord
self.y = ycoord
Better already, no?
Now, imagine you're looking at someone else's code, trying to use that. Their Points have a length() method that you can call. What do you expect that to do? What could that... possibly do? A number of things, all because length is an awful descriptor for something that a Point is doing. It's certainly not a property of the Point - a point is 0-dimensional.
So let's rethink that function. There are two obvious ways to make this API - your Point class could have a distance_to(other_point) method, that would accept one argument - another Point. Optionally, you could have a module-level function segment_length(point1, point2) that would give you the length of the segment defined by the two Point objects.
So, the module-level function:
def segment_length(p1, p2):
return math.sqrt((p2.x-p1.x)**2 + (p2.y-p1.y)**2)
I'll leave the Point method to you, should you wish to attempt it. It looks very similar, just using self in lieu of one of the points.
Lets walk through this:
p1 is an instance of the Segment class with attributes x=3, y=4.
p2 is an instance of the Segment class with attributes x=0, y=0,
When you set p2 to (5, 5) you could do it with p2 = Segment(5, 5),
s will have attributes x=p1 (an instance of Segment, not a coordinate) and y=p2 (another instance of Segment).
Calculating the length.
Your length method should look like this:
def length(self, xcoord, ycoord):
return math.sqrt(math.pow(xcoord - self.x,2)+math.pow(ycoord - self.y,2))
This now uses the x and y coordinates of the class instance (in the example below, p1) and calculates the length between them, and the xcoord and ycoord parameters provided.
And you would call this with:
p2x, p2y = p2.get()
print(p1.length(p2x, p2y))
Firstly, you're missing a second math.pow() in your line:
return math.sqrt(math.pow(xcoord-ycoord,2)+(xcoord-ycoord,2))
Secondly with your call s = Segment(p1, p2) the x and y values of your Segment s are equal to the segments p1 and p2.
At the moment your values should read:
p1.get()
> (3, 4)
p2.get()
> (5, 5)
After the assignment of s you get:
s.get()
> ((3, 4), (5, 5))
This is problematic, because math.pow() has no idea what to do with a Segment object.

Categories