0

So for a task I need to be able to reflect the y-value of a tuple. This is what I have so far, but I keep getting this error: 'NoneType' object has no attribute 'print'

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def print(self):
        print((self.x, self.y))
    def reflect_x(self):
        if self.y < 0:
            print((self.x, abs(self.y)))
        if self.y > 0:
            print((self.x, -abs(self.y)))

if __name__ == "__main__":
    p1 = Point(1,4)
    p1.reflect_x().print()

    p2 = Point(-3,5)
    p2.reflect_x().print()

    p3 = Point(-3,-5)
    p3.reflect_x().print()

These are the values I should be getting:

(1, -4)
(-3, -5)
(-3, 5)

The bottom part (in if __name__ == "__main__":) is a test code which I'm not allowed to change, so the main problems should be lying in the top part, so basically inside the Point-class.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
sari023
  • 15
  • 2
  • 3
    I've taken a wild guess based on the look of the code that this is Python, and edited the tags so that someone who knows Python can find the question and help you. If that's wrong, please click [edit] and choose a more appropriate tag. If I'm right, you might also want to confirm the version of Python you're using. – IMSoP Oct 20 '21 at 17:49
  • 2
    `reflect_x()` is a method which is not returning anything. It has no `.print()` method associated with it because when you call `reflect_x()` it returns `None`. Also, your `reflect_x()` method *already* prints information, why are you separately trying to call `print()`? The only way this would work the way you intend would be to create a new instance of your Point class and return it from `reflect_x()`. – ddejohn Oct 20 '21 at 17:50
  • 1
    Maybe this is beside the point, but why are you using `-abs()`? For that matter, why not skip the `if`s and `abs()` entirely and just do `-self.y`? Maybe you ultimately want `self.y *= -1` – wjandrea Oct 20 '21 at 17:56

5 Answers5

1

The method reflect_x implicitly returns None. You have to either call the custom print method on the class object itself or return self in your reflect_x.

EDIT by call the custom print method on the class object itself I mean to change the last part of the code as follows

if __name__ == "__main__":
    p1 = Point(1,4)
    p1.reflect_x()
    p1.print()

    p2 = Point(-3,5)
    p2.reflect_x()
    p2.print()

    p3 = Point(-3,-5)
    p3.reflect_x()
    p3.print()

which will work because the custom print method is a member of the Point class.

And the second option of returning self from the reflect_x method will work as well because we return the reference of the object instance. See this: https://www.online-python.com/hHg4Ya3yG7

These two points only focus on the aspect to resolve the 'NoneType' object has no attribute 'print' issue. To achieve the results we are looking for, modify the code like so:

def reflect_x(self):
    if self.y < 0:
        self.y = abs(self.y)
    elif self.y > 0:
        self.y = -abs(self.y)
    return self

which will print the desired result of

(1, -4)
(-3, -5)
(-3, 5)
wjandrea
  • 28,235
  • 9
  • 60
  • 81
tafaust
  • 1,457
  • 16
  • 32
1

Your method Point.reflect_x() doesn't have a return, so it returns None. You are trying to call the function print in Point.reflect_x(), wich is the source of your error.

To solve this, just call Point.print() instead of Point.reflect_x().print()

if __name__ == "__main__":
    p1 = Point(1,4)
    p1.reflect_x()
    p1.print()

    p2 = Point(-3,5)
    p2.reflect_x()
    p2.print()

    p3 = Point(-3,-5)
    p3.reflect_x()
    p3.print()

Also, change your reflect_x method:

def reflect_x(self):
    self.y *= -1
1

Your reflect function doesn't change the class - it returns None, which doesn't have a print function, as the error says

To "reflect over the X-axis", you don't need absolute values, just multiply by negative one

Plus, adding a print method to the class is not Pythonistic. You should implement __str__

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'

    def reflect_x(self):
        self.y *= -1

Then you can do

p1 = Point(1,4)
print(p1)
p1.reflect_x()
print(p1)

If you need the exact code shown in the main execution part and can only change the class, then

change only

def reflect_x(self):
    self.y *= -1
    return self

Then this will work

p1 = Point(1,4)
p1.reflect_x().print()
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • 1
    +1, I'm out of votes for today. This is really the only answer that attempts to fix the *real* issues with OP's code. – ddejohn Oct 20 '21 at 17:57
  • First of all thank you. Unfortunately, the bottom part is a test code which I'm not allowed to change, so there must be something else that I should be changing on the Point-class, but I genuinely have no clue what it is. – sari023 Oct 20 '21 at 18:25
  • @sari023 I've updated my answer with those changes – OneCricketeer Oct 20 '21 at 18:40
  • 1
    @One FYI I posted [my own answer](/a/69651438/4518341) taking the opposite strategy (new instance instead of `self`). – wjandrea Oct 20 '21 at 18:44
1

reflect_x() should return a Point object.

def reflect_x(self):
    cls = type(self)
    return cls(self.x, -self.y)

It'd also be possible to modify self then return it, but conventionally, mutators return None in Python to avoid confusion.

By the way, this style facilitates method chaining, and it's commonly used in Pandas for example.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
0

Remove the .print() after p1.reflect_x:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def print(self):
        print(self.x, self.y)
        
    def reflect_x(self):
        if self.y < 0:
            print((self.x, abs(self.y)))
        if self.y > 0:
            print((self.x, -abs(self.y)))

if __name__ == "__main__":
    p1 = Point(1,4)
    p1.reflect_x()

    p2 = Point(-3,5)
    p2.reflect_x()

    p3 = Point(-3,-5)
    p3.reflect_x()
Anteino
  • 1,044
  • 7
  • 28
  • 1
    This will print that function output. Seems OP wants to print the instance after calling that function (as well) – OneCricketeer Oct 20 '21 at 17:53
  • I think that wasn't their intention. Anyway, with this edit the output gets printed as shown in the question. – Anteino Oct 20 '21 at 17:55