So i'am new into classes in python, and i was struggling a little bit here :(. So I wanted to make a class point which contained coordinates (x, y). First I made a function which set the values and afterwards a function to print the values in a tuple. But then i wanted to manipulate the y coordinate to reflect along the x-axis. But suddenly it started to give me an AttributeError
Input:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print(self):
i = (self.x, self.y)
print(tuple(i))
def reflect_x(self):
self.y*=-1
p1 = Point(1,4)
p1.print()
p2 = Point(-3,5)
p2.print()
p3 = Point(-3,-5)
p3.reflect_x().print()
Output:
(1, 4)
(-3, 5)
Traceback (most recent call last):
File "/I'd/love/to/keep/this/private/Oef.py", line 22, in <module>
p3.reflect_x().print()
AttributeError: 'NoneType' object has no attribute 'print'
As you can se as long as i don't implement my reflect_x function I don't get an error.
My wish-to output:
(1, -4)
(-3, -5)
(-3, 5)
Thank you in advance <3
As it was already pointed out, reflect_x() returns default value (None), since you didn't put any return there. If you are used to the programming language that endorses chaining methods, you should add return self in functions you wanna use like that.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print(self):
i = (self.x, self.y)
print(tuple(i))
return self # change here
def reflect_x(self):
self.y*=-1
return self # change here
p1 = Point(1,4)
p1.print()
p2 = Point(-3,5)
p2.print()
p3 = Point(-3,-5)
p3.reflect_x().print()
therefore allowing your methods to be chainable. A nice video about it.
it seems like you are trying to print the state of your p3 Object after calling reflect_x, right?
For that I would suggest to use p3.print() below your last line like you did before. You cannot call print that way, because it is trying to find it as a function of what reflect_x returns, which is None, and not you Class.
Apply it directly to the object:
p3 = Point(-3,-5)
p3.reflect_x()
p3.print()
As opposed to the result of reflect_x(), which doesn't return anything.
Yeah it's quite simple. When you call the p3.reflect_x().print(), it means you call the print() function from the p3.reflect_x() object. But the p3.reflect_x() means the object return from reflect_x() function of p3 object. And here it is None because you dont return any thing from your code. So you just add the return in reflect_x() function and it will work. It will look like this:
def reflect_x(self):
self.y*=-1
return self
Related
I'm studying operator overloading in Python and came accross with this chunk of code. It is not clear to me, why do we return Point(x,y) in add function instead of just returning x and y.
class Point:
def __init__(self, x=0 , y=0):
self.x = x
self.y = y
def __str__(self):
return("({0},{1})" .format(self.x, self.y))
def __add__(self , other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y) // here if we remove Point object and use return(x,y) it does not cause any errors
p1 = Point(1,5)
p2 = Point(2,5)
print(p1 + p2)
The (x,y) syntax creates a tuple object, while Point(x,y) creates an instance of the Point class and sets it's x and y properties.
There is a difference between these two types of python objects. A tuple is a sequence type object, which is formal talk for a list of values. A tuple, by itself, only has the two values, and the methods that apply for that type of collection. You can read more about tuples here: https://docs.python.org/3.3/library/stdtypes.html?highlight=tuple#tuple
On the other hand, while your Point class is still quite simple, can have much additional functionality via other methods. For example, the tuple will probably not have the add() method you are creating in your point class, or it may have another add() method which does something else. Hope this clears this up.
Just learning python and I write simple code along the way.
Overriding the print method in the derived class, can I print both classes in the same line, without changing the base class?
i.e. I want pointA.print() to print
"x = 10 and y = 10 and z = 10"; not x = 10 and y = 10 and z = 10
I know in C# this can be done easily as the WriteLine method starts with a new line (as opposed to ending with it), and so, the Write method does what I expected it to.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print(self):
print(f"x = {self.x} and y = {self.y}")
class PointWithZAxis(Point):
def __init__(self, x, y, z):
Point.__init__(self, x, y)
self.z = z
def print(self):
Point.print(self)
print(f"and z = {self.z}")
pointA = PointWithZAxis(10, 10, 10)
pointA.print()
Change the print in the parent class to this:
print(f"x = {self.x} and y = {self.y}", end = "")
BTW, it is cleaner in my opinion to overwrite the __str__ method of the classes than to make a print() method. The __str__ method of an object is automatically called when you print the object (like: print(object)). The code then becomes:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"x = {self.x} and y = {self.y}"
class PointWithZAxis(Point):
def __init__(self, x, y, z):
Point.__init__(self, x, y)
self.z = z
def __str__(self):
return super().__str__() + f"and z = {self.z}"
pointA = PointWithZAxis(10, 10, 10)
print(pointA)
You can add end="" to print
print("something", end="")
Adding the end argument to the print function lets you specify the ending of you print statement, so:
print(..., end='')
By default it is set to end='\n', which indicates a new line.
P.S. be careful with naming funcions print as they shadow already existing functions and may cause confusion.
There are a couple other people who are responding with print(..., end=""). This is a quick-fix, sure. But there's something else I'd like to point out.
Since you're a beginner, I'd say you've encountered a good example that teaches why you should think a little about the kind of APIs/interfaces you're designing. Take a step back and ask yourself this question: "Who are the consumers (callers) of def print(self)? And what do they want." The point here is, you can have different callers each wanting a different thing. These problems arise when you're not able to find the common denominator across all that they want. Introducing parameters to the function is one way. In other words: your derived class can send in a additional parameter asking to not append a newline, while those that call from outside of PointWithZAxis.print(..) need not know about this parameter.
Here's an average solution:
class Point:
....
def print(self, include_newline=True):
print(..., end=("\n" if include_newline else ""))
class PointWithZAxis:
def print(self):
Point.print(self, include_newline=False)
print(....)
Here's a good solution (Don't print. How about making the job just to construct a string? Actual printing can be the callers job).
class Point:
....
def get_print_string(self):
return f"x = {self.x} and y = {self.y}"
class PointWithZAxis:
def get_print_string(self):
return super().get_print_string() + f" and z = {self.z}"
# You can then do:
p = PointWithZAxis()
print(p.get_print_string())
Pythonic solution (recommended): Use __str__(..). This is the recommended way of doing what get_print_string() does.This function indirectly gets called when you do print(AnyClass()). Refer to #Bram Dekker's solution.
To get to the point I'm learning how to work classes and list comprehension and I'm running into this problem:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def are_in_first_quadrant(listPoint):
newListPoint = filter(lambda pnt: pnt.x > 0 and pnt.y > 0, listPoint)
return newListPoint
pList = [Point(-3,7), Point(2,3), Point(7,0), Point(6,-9), Point(7,9)]
newList = are_in_first_quadrant(pList)
So you can see the goal of this is to spew out a list of points that are in the first quadrant, but when I try to print 'newList' I get:
[<objects.Point instance at 0x0293FA08>, <objects.Point instance at 0x0293FA80>]
Instead of:
[Point(2,3) , Point(7.9)]
Looking over this post: Filters in Python3
I understand the print out is the memory location but I don't really gain much more from that.
So question is how exactly do I fix this?
I'm guessing it probably has to do with how I used lambda but again not too sure.
I'm using Python 2.7
Thanks in advance.
Edit:
Also just tried
def are_in_first_quadrant(listPoint):
newListPoint = [pnt for pnt in listPoint if pnt.x > 0 and pnt.y > 0]
return newListPoint
and it throws up the same thing.
You need to provide a __repr__() method for your Point class:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return "Point({}, {})".format(self.x, self.y)
This method will be called for each element when the list is printed.
Just a remark: a function called are_... (or is_...) is supposed to return True or False. A more suitable name would be points_in_first_quadrant().
For a comparison between __str__() and __repr__(), see this question.
I have a general question on the class definition and its use..THe below code from one of the book works fine but I have a general questions.
Here we have defined a class Point and creating 2 instance Point1 & Point2. When calculating the distance for point2, how can we pass the point1 object?
Isn't point1 the point object, whereas the other_point is reprented as a variable.
Im little confused.
Code:
import math
class Point:
def move(self, x, y):
self.x = x
self.y = y
def reset(self):
self.move(0, 0)
def calculate_distance(self, other_point):
print("Inside calculating distance")
return math.sqrt(
(self.x - other_point.x)**2 +
(self.y - other_point.y)**2)
point1 = Point()
point2 = Point()
point1.reset()
point2.move(5,0)
print(point2.calculate_distance(point1))
When you create a Point object, several things happen.
point1 = Point()
point2 = Point()
One of the things that happens is that any methods belonging to the Point class are bound. What this means is that one of the arguments in the method is fixed, so that it always refers to the instance created. Let's look at the definition of calculate_distance.
def calculate_distance(self, other_point):
print("Inside calculating distance")
return math.sqrt(
(self.x - other_point.x)**2 +
(self.y - other_point.y)**2)
You can probably guess which argument is fixed. When Point() is called and an instance is created, the self parameter of calculate_distnace is fixed so that it always refers to that instance. So whenever you do this:
point1.calculate_distance(x)
You're doing the equivalent of this:
Point.calculate_distance(point1, x)
And whenever you do this:
point2.calculate_distance(point1)
You're doing the equivalent of this:
Point.calculate_distance(point2, point1)
That's what the self variable does. So when you are inside the definition of a class, you can use self to identify the object whose data you are trying to manipulate.
For example, suppose you have a class called human (which has a member variable named age), and every year, you want to increase the age of that human by calling the increment_age function. Then, you could write the following code:
class Human:
def __init__(self):
self.age = 0
def increment_age(self):
self.age += 1
>>> h = Human()
>>> print h.age
0
>>> h.increment_age()
>>> print h.age
1
So you see, by calling self, you are referring to the object itself. In your example, this would translate to self referring to point1.
Now, suppose that in the Human class, we want to add a function that allows two humans to fight. In this case, one human would have to fight another human (suppose that fighting another human increases your life by one and decreases the other human's life by one). In that case, you could write the following function within the Human class:
def fight(self, other_human):
self.age += 1
other_human.age -= 1
Now:
>>> h1 = Human()
>>> h2 = Human()
>>> h1.age = 5
>>> h2.age = 3
>>> print h1.age
5
>>> print h2.age
3
>>> h1.fight(h2)
>>> print h1.age
6
>>> print h2.age
2
Thus you can see in this example that h2 is the other_human in the fight function.
Hope that helps
Given your code, point2.calculate_distance(point1) calls calculate_distance with the object referred to by point2 as self, and the object referred to by point1 as other_point.
A good way to learn about these sorts of things is to use a visual debugger, and inspect the values in stack frames as the calls are made.
Inside calculate_distance, other_point is the name used to refer to whatever object is passed as an argument.
Let's say I've got a variable A that is the result of a function/expression F. F in it's turn has a number of other variables in it, let's say X,Y and Z.
Is it possible to bind A to F so that whenever X,Y or Z changes, A will be updated automatically?
What I want to avoid is that everytime X,Y and Z changes, I have to remember to update A explicitly in the code. I also don't want to call the function everytime I want to use the A.
Example (as per requested): I've got the following function:
def calcHits():
return sum(hitDiceRolls,level*modList['con'])
and in my program (outside of the function), I've got a variable called hitPoints (yes, it's a roleplaying game program). Whenever the variables that's used in the function is changed, I want hitPoints to change as well.
The typical way to do this in Python would be to use a class:
class ExpressionBinder:
def __init__(self, f):
self.f = f
self.x = 0
self.y = 0
self.z = 0
#property
def result(self):
return self.f(self.x, self.y, self.z)
You can use it like this:
def f(x, y, z):
return x**3 + y**2 + z
b = ExpressionBinder(f)
b.x = 1
b.y = 2
b.z = 3
print(b.result)
There is no way in Python to automatically rebind a name in global or local scope in response to other names being rebound. However, it should be possible to make a class that can keep track of some values and have a member function that returns the value you called A. And, as #Alok pointed out, you can use property descriptors to make a member name that implicitly calls a function to return its value, so you can hide the function and treat the name like a plain old name.
class Trk(object):
"""Track some values and compute a function if any change"""
def __init__(self, name, fn, **objects_to_track):
def _trk_fn(self):
if any(self.__dict__[x] != self.original_objects[x] for x in self.original_objects):
self.value = self.saved_fn(self.__dict___)
# now that self.value is updated, also update self.original_objects
for x in self.original_objects:
self.original_objects[x] = self.__dict__[x]
return self.value
self.original_objects = objects_to_track # make reference copy
self.__dict__.update(objects_to_track)
self.name = name
self.saved_fn = fn
self.fn = self._trk_fn()
self.value = self.fn()
I'm sorry but I am very tired right now, and I canot finish this example. I didn't test it either. But this shows one way to track values, and if they are different, do something different. You use it like this:
# want to track x, y, z
trk = Trk(x, y, z)
trk.fn() # returns up-to-date value
trk.x = new_value
trk.fn() #detects that trk.x changed and computes new trk.value
If the above works, you can use the property descriptor stuff to bind a name such that an attempt to read a value from the name will call self.fn()
EDIT: Oh, it's important that when self.value is updated, self.original_objects should be updated. I've added code to do that.
And now I'm going to sleep!