运行Python分形程序出现NameError:'Fractal'未定义,如何修复?
修复分形图形生成代码的NameError及其他问题
核心错误原因
你所有的分形类(比如SierpinskiTriangle)都声明继承自Fractal类,但代码里从未定义过这个基类,这是触发NameError: name 'Fractal' is not defined的直接原因。
完整修复步骤
1. 添加Fractal基类
在ChaosGame类之后、分形类之前,定义Fractal基类,封装所有分形共有的属性和方法:
class Fractal: def __init__(self, dimensions): self.dimensions = dimensions # 设置默认参数,子类可按需覆盖 self.num_points = 100000 # 默认生成点数 self.triangle = 0.5 # 默认比例因子 # 实现子类用到的相对坐标计算方法 def frac_x(self, fraction): return self.dimensions["MIN_X"] + fraction * (self.dimensions["MAX_X"] - self.dimensions["MIN_X"]) def frac_y(self, fraction): return self.dimensions["MIN_Y"] + fraction * (self.dimensions["MAX_Y"] - self.dimensions["MIN_Y"])
2. 修复分形类的初始化参数
所有分形类的__init__方法接收的是dimensions(从ChaosGame传入的是self.dimensions),原代码错误写成了canvas,需要修正。同时用super()替代直接调用Fractal.__init__,写法更规范:
class SierpinskiTriangle(Fractal): def __init__(self, dimensions): super().__init__(dimensions) v1 = Point(self.dimensions["MID_X"], self.dimensions["MIN_Y"]) v2 = Point(self.dimensions["MIN_X"], self.dimensions["MAX_Y"]) v3 = Point(self.dimensions["MAX_X"], self.dimensions["MAX_Y"]) self.vertices = [v1, v2, v3] self.triangle = 0.5 # 补充谢尔宾斯基三角形的比例因子
3. 修复拼写与逻辑错误
SierpinskiCarpet里的self.traingle拼写错误,改成self.triangle- 修正
SierpinskiCarpet中重复的顶点(原代码存在多个重复顶点,导致分形生成异常),替换为8个不重复的顶点
4. 补充缺失的interpt方法
原代码中Pentagon、Hexagon等类调用了p.interpt(),但Point类里没有实现这个方法,需要添加:
# 在Point类中添加 def interpt(self, a, factor): # 计算两点之间按factor比例的插值点 return Point(self.x + (a.x - self.x)*factor, self.y + (a.y - self.y)*factor)
5. 修正Pentagon的坐标计算
原Pentagon的角度用了度数,但cos/sin函数接收的是弧度,导致坐标计算错误,需要将度数转为弧度:
class Pentagon(Fractal): def __init__(self, dimensions): super().__init__(dimensions) # 将60度转为弧度 offset_rad = 60 * PI / 180 radius = min(self.dimensions["MID_X"], self.dimensions["MID_Y"]) * 0.8 v1 = Point(self.dimensions["MID_X"] + radius * cos(2 * PI / 5 + offset_rad), self.dimensions["MID_Y"] + radius * sin(2 * PI / 5 + offset_rad)) # 其余顶点同理修正...
完整修复后的代码
from tkinter import * from math import sqrt, sin, cos, pi as PI from random import randint # 2D点类 class Point(object): def __init__(self, x=0.0, y=0.0): self._x = float(x) self._y = float(y) # 属性访问器和修改器 @property def x(self): return self._x @x.setter def x(self, value): self._x = value @property def y(self): return self._y @y.setter def y(self, value): self._y = value # 计算两点距离 def dist(self, a): return sqrt((self.x - a.x)**2 + (self.y - a.y)**2) # 计算中点 def midpt(self, a): return Point((self.x + a.x)/2, (self.y + a.y)/2) # 自定义插值方法(用于谢尔宾斯基三角形) def magic(self, a, triangle): trianglex = triangle if self.x > a.x: trianglex = 1.0 - triangle triangley = triangle if self.y > a.y: triangley = 1.0 - triangle x = abs(self.x - a.x) * trianglex + min(self.x, a.x) y = abs(self.y - a.y) * triangley + min(self.y, a.y) return Point(x, y) # 通用插值方法(用于其他分形) def interpt(self, a, factor): return Point(self.x + (a.x - self.x)*factor, self.y + (a.y - self.y)*factor) # 字符串表示 def __str__(self): return f"({self.x}, {self.y})" # 画布坐标系类,继承自Tkinter的Canvas class ChaosGame(Canvas): def __init__(self, master): Canvas.__init__(self, master, bg="white") self.pack(fill=BOTH, expand=1) # 设置画布尺寸、点半径和颜色 self.dimensions = {"MIN_X":2, "MAX_X":WIDTH-9, "MIN_Y":2, "MAX_Y":HEIGHT-9} self.dimensions["MID_Y"] = (self.dimensions["MIN_Y"] + self.dimensions["MAX_Y"]) / 2 self.dimensions["MID_X"] = (self.dimensions["MIN_X"] + self.dimensions["MAX_X"]) / 2 self.vertexRadius = 1 self.vertexColor = "blue" self.pointRadius = 0 self.pointColor = "black" # 绘制分形点 def plot_Values(self, fractal_name): if fractal_name == "SierpinskiTriangle": p1 = SierpinskiTriangle(self.dimensions) for vertex in p1.vertices: self.plot_point(vertex, self.vertexColor, self.vertexRadius) p = p1.vertices[randint(0, len(p1.vertices)-1)] for _ in range(p1.num_points): p = p.magic(p1.vertices[randint(0, len(p1.vertices)-1)], p1.triangle) self.plot_point(p, self.pointColor, self.pointRadius) elif fractal_name == "Pentagon": p1 = Pentagon(self.dimensions) for vertex in p1.vertices: self.plot_point(vertex, self.vertexColor, self.vertexRadius) p = p1.vertices[randint(0, len(p1.vertices)-1)] for _ in range(p1.num_points): p = p.interpt(p1.vertices[randint(0, len(p1.vertices)-1)], p1.triangle) self.plot_point(p, self.pointColor, self.pointRadius) elif fractal_name == "Hexagon": p1 = Hexagon(self.dimensions) for vertex in p1.vertices: self.plot_point(vertex, self.vertexColor, self.vertexRadius) p = p1.vertices[randint(0, len(p1.vertices)-1)] for _ in range(p1.num_points): p = p.interpt(p1.vertices[randint(0, len(p1.vertices)-1)], p1.triangle) self.plot_point(p, self.pointColor, self.pointRadius) elif fractal_name == "Octagon": p1 = Octagon(self.dimensions) for vertex in p1.vertices: self.plot_point(vertex, self.vertexColor, self.vertexRadius) p = p1.vertices[randint(0, len(p1.vertices)-1)] for _ in range(p1.num_points): p = p.interpt(p1.vertices[randint(0, len(p1.vertices)-1)], p1.triangle) self.plot_point(p, self.pointColor, self.pointRadius) elif fractal_name == "SierpinskiCarpet": p1 = SierpinskiCarpet(self.dimensions) for vertex in p1.vertices: self.plot_point(vertex, self.vertexColor, self.vertexRadius) p = p1.vertices[randint(0, len(p1.vertices)-1)] for _ in range(p1.num_points): p = p.interpt(p1.vertices[randint(0, len(p1.vertices)-1)], p1.triangle) self.plot_point(p, self.pointColor, self.pointRadius) # 绘制单个点 def plot_point(self, point, color, radius): self.create_oval(point.x, point.y, point.x + 2*radius, point.y + 2*radius, outline=color, fill=color) # 分形基类,所有分形类继承此类 class Fractal: def __init__(self, dimensions): self.dimensions = dimensions self.num_points = 100000 self.triangle = 0.5 # 计算X轴相对坐标 def frac_x(self, fraction): return self.dimensions["MIN_X"] + fraction * (self.dimensions["MAX_X"] - self.dimensions["MIN_X"]) # 计算Y轴相对坐标 def frac_y(self, fraction): return self.dimensions["MIN_Y"] + fraction * (self.dimensions["MAX_Y"] - self.dimensions["MIN_Y"]) # 谢尔宾斯基三角形分形 class SierpinskiTriangle(Fractal): def __init__(self, dimensions): super().__init__(dimensions) v1 = Point(self.dimensions["MID_X"], self.dimensions["MIN_Y"]) v2 = Point(self.dimensions["MIN_X"], self.dimensions["MAX_Y"]) v3 = Point(self.dimensions["MAX_X"], self.dimensions["MAX_Y"]) self.vertices = [v1, v2, v3] self.triangle = 0.5 # 谢尔宾斯基地毯分形 class SierpinskiCarpet(Fractal): def __init__(self, dimensions): super().__init__(dimensions) v1 = Point(self.dimensions["MIN_X"], self.dimensions["MIN_Y"]) v2 = Point(self.dimensions["MID_X"], self.dimensions["MIN_Y"]) v3 = Point(self.dimensions["MAX_X"], self.dimensions["MIN_Y"]) v4 = Point(self.dimensions["MIN_X"], self.dimensions["MID_Y"]) v5 = Point(self.dimensions["MAX_X"], self.dimensions["MID_Y"]) v6 = Point(self.dimensions["MIN_X"], self.dimensions["MAX_Y"]) v7 = Point(self.dimensions["MID_X"], self.dimensions["MAX_Y"]) v8 = Point(self.dimensions["MAX_X"], self.dimensions["MAX_Y"]) self.vertices = [v1, v2, v3, v4, v5, v6, v7, v8] self.num_points = 100000 self.triangle = 0.66 # 五边形分形 class Pentagon(Fractal): def __init__(self, dimensions): super().__init__(dimensions) offset_rad = 60 * PI / 180 radius = min(self.dimensions["MID_X"], self.dimensions["MID_Y"]) * 0.8 v1 = Point(self.dimensions["MID_X"] + radius * cos(2 * PI / 5 + offset_rad), self.dimensions["MID_Y"] + radius * sin(2 * PI / 5 + offset_rad)) v2 = Point(self.dimensions["MID_X"] + radius * cos(4 * PI / 5 + offset_rad), self.dimensions["MID_Y"] + radius * sin(4 * PI / 5 + offset_rad)) v3 = Point(self.dimensions["MID_X"] + radius * cos(6 * PI / 5 + offset_rad), self.dimensions["MID_Y"] + radius * sin(6 * PI / 5 + offset_rad)) v4 = Point(self.dimensions["MID_X"] + radius * cos(8 * PI / 5 + offset_rad), self.dimensions["MID_Y"] + radius * sin(8 * PI / 5 + offset_rad)) v5 = Point(self.dimensions["MID_X"] + radius * cos(10 * PI / 5 + offset_rad), self.dimensions["MID_Y"] + radius * sin(10 * PI / 5 + offset_rad)) self.vertices = [v1, v2, v3, v4, v5] self.triangle = 0.618 # 六边形分形 class Hexagon(Fractal): def __init__(self, dimensions): super().__init__(dimensions) v1 = Point(self.dimensions["MID_X"], self.dimensions["MIN_Y"]) v2 = Point(self.dimensions["MIN_X"], self.frac_y(0.25)) v3 = Point(self.dimensions["MAX_X"], self.frac_y(0.25)) v4 = Point(self.dimensions["MIN_X"], self.frac_y(0.75)) v5 = Point(self.dimensions["MAX_X"], self.frac_y(0.75)) v6 = Point(self.dimensions["MID_X"], self.dimensions["MAX_Y"]) self.vertices = [v1, v2, v3, v4, v5, v6] self.triangle = 0.665 # 八边形分形 class Octagon(Fractal): def __init__(self, dimensions): super().__init__(dimensions) v1 = Point(self.frac_x(0.2925), self.dimensions["MIN_Y"]) v2 = Point(self.frac_x(0.7075), self.dimensions["MIN_Y"]) v3 = Point(self.dimensions["MIN_X"], self.frac_y(0.2925)) v4 = Point(self.dimensions["MAX_X"], self.frac_y(0.2925)) v5 = Point(self.dimensions["MIN_X"], self.frac_y(0.7075)) v6 = Point(self.dimensions["MAX_X"], self.frac_y(0.7075)) v7 = Point(self.frac_x(0.2925), self.dimensions["MAX_Y"]) v8 = Point(self.frac_x(0.7075), self.dimensions["MAX_Y"]) self.vertices = [v1, v2, v3, v4, v5, v6, v7, v8] self.num_points = 75000 self.triangle = 0.705 # 主程序 WIDTH = 700 HEIGHT = 550 FRACTALS = ["SierpinskiTriangle", "SierpinskiCarpet", "Pentagon", "Hexagon", "Octagon"] # 逐个生成分形窗口 for fractal in FRACTALS: window = Tk() window.geometry(f"{WIDTH}x{HEIGHT}") window.title("混沌游戏 - 分形生成") canvas = ChaosGame(window) canvas.plot_Values(fractal) window.mainloop()
内容的提问来源于stack exchange,提问作者Makayla Willams
相关产品推荐
相关产品推荐

