You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:55:16