0

Why can't I call an attribute of a class, if I call it from an array of same Objects? For example, I have a class Point and want to create an array of n such Points: arr = [Point() for i in range(n)]. Then I want to take an x and a y of these points. I write print(arr[<index>].x, arr[<index>].y). If I do that in python it works but when I try the same with cython, even without defining types, it says, that I don't have an attribute x in the class Point. However, if I don't use an array and just create a single object point = Point(), then the program works just fine when I write print(point.x, point.y. Here is code in python:

class Point():
    def __init__(self, x = 0., y = 0.0):
        self.x = x
        self.y = y
        # print(self.x, self.y)

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

def debug():
    debug_arr = list([Point(i, i + 1) for i in range(1)])
    debug_point = Point(1, 2)
    print('debug_point by hand:', debug_point.x, debug_point.y)
    print('debug_point with __str__ function:', debug_point)
    print('debug_arr:', debug_arr)
    print('debug by taking index and argument:', debug_arr[0].x, debug_arr[0].y)

debug()

Output:

debug_point by hand: 1 2
debug_point with __str__ function: 1, 2
debug_arr: [<__main__.Point object at 0x000002B79F025FD0>]
debug by taking index and argument: 0 1

The same code in cython:

cdef class Point():
    cdef double x, y

    def __init__(self, x: double = 0., y: double = 0.0):
        self.x = x
        self.y = y
        # print(self.x, self.y)

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


def debug():
    debug_arr = list([Point(i, i + 1) for i in range(1)])
    debug_point = Point(1, 2)
    print('debug_point by hand:', debug_point.x, debug_point.y)
    print('debug_point with __str__ function:', debug_point)
    print('debug_arr:', debug_arr)
    print('debug by taking index and argument:', debug_arr[0].x, debug_arr[0].y)

def main():
    debug()

Output:

debug_point by hand: 1.0 2.0
debug_point with __str__ function: 1.0, 2.0
debug_arr: [<main.Point object at 0x0000025AF0C45C00>]
Traceback (most recent call last):
  File "C:\*******\Program.py", line 2, in <module>
    main.main()
  File "main.pyx", line 131, in main.main
    debug()
  File "main.pyx", line 128, in main.debug
    print('debug by taking index and argument:', debug_arr[0].x, debug_arr[0].y)
AttributeError: 'main.Point' object has no attribute 'x'
  • I think you need to check debug_arr variable. I mean print it and see what's inside also you can check with a for loop. For example; ```for i in debug_arr: print(i); print(i.x) `` So that you can understand what is going on and solve your problem.. – Can İlgu Feb 05 '21 at 17:03
  • Ok, I added this loop. When I print `i`, it gives me the coordinates. But when it comes to `print(i.x)` it breaks with the same problem: `File "main.pyx", line 130, in main.debug print('its x coordinate:', i.x) AttributeError: 'main.Point' object has no attribute 'x' ` – chickysnail Feb 05 '21 at 17:16
  • 1
    This is effectively a variation of https://stackoverflow.com/questions/55230665/cython-class-attributeerror - Cython can only access attributes of `cdef classes` if it knows the type of that class at compile-time. When reading from a list it only knows that it's a Python object – DavidW Feb 05 '21 at 17:36
  • Oh, thank you so much, it works. I was trying to find the problem for a day. Anyway, you can write your comment as an answer and I will mark it as an answer (I guess it will give you some reputation). By the way, why does `point.x` still works, if I didn't make attribute x public? – chickysnail Feb 05 '21 at 17:52
  • In Cython, `public` means "accessible from Python" - it isn't like C++ where it means "no access from outside the class". Cython can always access `cdef` attributes (provided in knows they exist) – DavidW Feb 05 '21 at 18:42

0 Answers0