错误与行号有关,与代码无关。如何解决?

Error connected with line number and not the code. How to fix it?

我正在编写一个自学习汽车的程序,该程序可以行驶到 pygamecython 的点。我认为问题是由 cython 编译器而不是 pygame 引起的,因为在该方法中与 pygame 没有任何联系。但是,当我对 .pyd 文件进行 cython 化时,没有给出任何错误。另外,如果我更改任何行的代码,例如,在错误所在的第 99 行之前添加一行,错误行不会移动一个,它会留在第 99 行。因此,错误以某种方式与行号而不是代码有关。这怎么可能? 这是 class 和我遇到错误的方法:

cdef class Car:
    cdef:
        double speed, car_angle, wheel_angle
        Point position
        Polygon shape

    def __init__(self, position=(0.0, 0.0), speed=0.5, car_angle=0.0, wheel_angle=0.0):
        self.position = Point(*position)
        self.shape = Polygon(self.position, CAR_SHAPE[0], CAR_SHAPE[1], self.car_angle)
        self.speed = speed
        self.car_angle = car_angle  # from -pi to pi
        self.wheel_angle = wheel_angle  # from -MAX_WHEEL_ANGLE to MAX_WHEEL_ANGLE

一个错误:

Traceback (most recent call last):
  File "main.pyx", line 83, in main.Population.__init__
    self.cars = [Car(position=CAR_START_POS, car_angle=random.random() * 2 - 1) for _ in range(amount)]
  File "main.pyx", line 99, in main.Car.__init__
    self.car_angle = car_angle  # from -pi to pi
AttributeError: 'main.Car' object has no attribute 'shape'
Exception ignored in: 'main.main'
Traceback (most recent call last):
  File "main.pyx", line 83, in main.Population.__init__
    self.cars = [Car(position=CAR_START_POS, car_angle=random.random() * 2 - 1) for _ in range(amount)]
  File "main.pyx", line 99, in main.Car.__init__
    self.car_angle = car_angle  # from -pi to pi
AttributeError: 'main.Car' object has no attribute 'shape'

编辑:如您所见,错误在第 99 行,但第 99 行是

self.car_angle = car_angle  # from -pi to pi

与属性形状无关。 我已经在 init 函数之前得到了 class Car 的所有定义。而属性形状也在里面。那为什么说没有这个属性呢?

我正在使用 python 3.8,cython 0.29.21 这是完整的代码,如果你需要的话:

import random
from math import sin, cos, pi, sqrt

import numpy as np
import pygame

pygame.init()
cdef:
    tuple BG_COLOR = (10, 10, 20)
    tuple SIZE = (800, 600)
    double MAX_WHEEL_ANGLE = 0.872665
    tuple CAR_COLOR = (200, 200, 200)
    tuple CAR_SHAPE = (23, 10)
    tuple CAR_START_POS = (SIZE[0] / 2, SIZE[1])
    clock = pygame.time.Clock()
    font = pygame.font.SysFont("Arial", 18)
    screen = pygame.display.set_mode(SIZE, pygame.NOFRAME)

def update_fps():
    cdef:
        str fps = str(int(clock.get_fps()))
        fps_text = font.render(fps, True, pygame.Color("coral"))
    return fps_text

cdef class Point():
    cdef double x, y
    cdef shift_x, shift_y

    def __init__(self, double x, double y):
        self.x = x
        self.y = y

    def __str__(self):
        return self.x, self.y

    cdef tuple to_array(self):
        return (self.x, self.y)

    cdef void rotate(self, Point center, double sine, double cosine):
        self.x = cosine * (self.x - center.x) + sine * (self.y - center.y) + center.x
        self.y = -sine * (self.x - center.x) + cosine * (self.y - center.y) + center.y

cdef class Polygon():
    cdef:
        Point center, p1, p2, p3, p4
        double length, width, radius, angle, sine, cosine

    def __init__(self, center: Point, length: double, width: double, angle: double):
        self.center = center
        self.length = length
        self.width = width
        self.radius = sqrt(width ** 2 + length ** 2)
        self.p1 = Point(center.x - width / 2, center.y + length / 2)
        self.p2 = Point(center.x + width / 2, center.y + length / 2)
        self.p3 = Point(center.x + width / 2, center.y - length / 2)
        self.p4 = Point(center.x - width / 2, center.y - length / 2)

        self.angle = angle

        sine, cosine = sin(pi - self.angle), cos(pi - self.angle)
        self.p1.x, self.p1.y = self.shift_x(self.p1.x, self.p1.y, sine, cosine), self.shift_y(self.p1.x, self.p1.y, sine, cosine)
        self.p2.x, self.p2.y = self.shift_x(self.p2.x, self.p2.y, sine, cosine), self.shift_y(self.p2.x, self.p2.y, sine, cosine)
        self.p3.x, self.p3.y = self.shift_x(self.p3.x, self.p3.y, sine, cosine), self.shift_y(self.p3.x, self.p3.y, sine, cosine)
        self.p4.x, self.p4.y = self.shift_x(self.p4.x, self.p4.y, sine, cosine), self.shift_y(self.p4.x, self.p4.y, sine, cosine)


    cdef shift_x(self, double x, double y, sine, cosine):
        return cosine * (x - self.center.x) + sine * (y - self.center.y) + self.center.x

    cdef shift_y(self, double x, double y, sine, cosine):
        return -sine * (x - self.center.x) + cosine * (y - self.center.y) + self.center.y

    def __str__(self):
        return (self.p1, self.p2, self.p3, self.p4)

    cdef tuple to_array(self):
        return self.p1.to_array(), self.p2.to_array(), self.p3.to_array(), self.p4.to_array()

cdef class Population:
    cdef list cars

    def __init__(self, amount: int):
        self.cars = [Car(position=CAR_START_POS, car_angle=random.random() * 2 - 1) for _ in range(amount)]

    cdef void go(self):
        for car in self.cars:
            car.go()

cdef class Car:
    cdef:
        double speed, car_angle, wheel_angle
        Point position
        Polygon shape

    def __init__(self, position=(0.0, 0.0), speed=0.5, car_angle=0.0, wheel_angle=0.0):
        self.position = Point(*position)
        self.shape = Polygon(self.position, CAR_SHAPE[0], CAR_SHAPE[1], self.car_angle)
        self.speed = speed
        self.car_angle = car_angle  # from -pi to pi
        self.wheel_angle = wheel_angle  # from -MAX_WHEEL_ANGLE to MAX_WHEEL_ANGLE

    cdef void go(self):
        self.position.y -= np.cos(self.car_angle) * self.speed
        self.position.x += np.sin(self.car_angle) * self.speed
        self.car_angle += self.wheel_angle
        self.draw()

    cdef void draw(self):
        pygame.draw.polygon(screen, CAR_COLOR, self.shape.to_array(), 3)
        pygame.draw.circle(screen, (255, 0, 0), (self.position.x, self.position.y), 1)

cdef class DNA:
    pass

cpdef void main():
    cdef bint close_program = False
    cdef Population cars = Population(1000)

    while not close_program:
        screen.fill(BG_COLOR)
        cars.go()
        screen.blit(update_fps(), (10, 0))
        clock.tick(60)
        pygame.display.flip()

if __name__ == '__main__':
    main()

EDIT2: 最有可能的问题是 python 和 cython 版本。它创建的 .pyd 文件是 main.cp39-win_amd64,所以这意味着 cython 创建了一个文件用于 python 3.9,我使用 3.8,但试图从 3.8 转到 3.9。不幸的是,我不能将所有下载的库从 3.8 移动到 3.9,所以,继续使用旧版本。如果您知道如何移动所有库,请帮助我。否则,我不得不以某种方式说 cython 为 python 3.8 创建文件。而且我也不知道该怎么做。 因此,有 2 种可能的解决方案:

  1. 将所有库移动到 python 3.9
  2. 说 cython 编译器使用 3.8 版本

问题出在 cython 和 python 版本上。现在我在 python 3.9 上做这个项目。我下载了这个项目需要的所有库,但如果有人能帮助我将所有 python 3.8 库移动到 3.9 而无需手动下载它们,那就更好了。