所以,我正在尝试学习 python,每次我在这里发布问题都感觉像是屈服......
我正在尝试创建自己的 turtle.Turtle 类。
import turtle
class TurtleGTX(turtle.Turtle):
"""My own version of turtle"""
def __init__(self):
pass
my_turtle = TurtleGTX()
my_turtle.forward(10)
给出回溯:AttributeError:“TurtleGTX”对象没有属性“_position”。然后我了解到这是一个“私有变量”,根据官方 python 教程,我可以在我的子类 TurtleGTX 中修改/覆盖它。如何用像 turtle 这样大的程序来做到这一点似乎相当困难,这意味着我缺少一个更简单的问题解决方案。最后我学到了,这就是重点,但我仍然希望由社区运行它,看看是否有一种优雅的方法来创建 turtle.Turtle 的子类。 (下一步是让你的乌龟表现得与标准乌龟不同)
所以下面的评论让我觉得也许我可以这样做:
import turtle
class TurtleGTX(turtle.Turtle):
"""My own version of turtle"""
my_turtle = TurtleGTX()
my_turtle.forward(100)
实际运行!现在我要看看它会把我引向何方……有些事情告诉我,我可能已经向前迈了一步,向后退了两步,因为这意味着我将无法在我的子类上初始化任何东西……
总结 Ignacio 的回答和 orokusaki 的评论,你可能应该写类似的东西
import turtle
class TurtleGTX(turtle.Turtle):
"""My own version of turtle"""
def __init__(self,*args,**kwargs):
super(TurtleGTX,self).__init__(*args,**kwargs)
print("Time for my GTX turtle!")
my_turtle = TurtleGTX()
my_turtle.forward(100)
如果您在子类中重新定义一个方法(例如
__init__()
),那么您有责任调用父类的方法以尊重父类的行为。
继承
Turtle
并添加自定义功能(例如 turtle.jump()
)是一种诱人的模式。但我在这种模式上取得的成功有限,在大多数情况下我都会谨慎行事。
调用
t = Turtle()
(包括Turtle
的子类)将对象注册到海龟模块的内部海龟列表中。如果您不使用 _update()
禁用内部更新循环,则此列表每帧都会调用 turtle.tracer(0)
。这个内部乌龟不太可能像您的子类所期望的那样收集垃圾.
除了它们挂钩的更新/绘制内部结构外,
Turtle
有许多属性和方法可以很容易地与您的自定义属性和方法命名冲突(海龟模块中大约有 150 个这样的名称,不包括双下划线) .当调用 self.left()
时,可能很难记住这是对超类还是派生类的 turtle 方法调用。通过将 turtle 组合为一个属性而不是一个子类,self.turtle.left()
使所有权完全清晰,代价是有点冗长。
这里有一组继承的替代方案,其中一些只对特定目的有用,但为了完整性还是列在这里:
如果你不介意海龟没有被垃圾收集(你正在制作一个你计划保留的固定数量),你可以分配一个自定义类的实例,每个实例都有一个内部
self.turtle = Turtle()
实例从包装器以正常方式操作。这是composition方法。
self.left(n)
方法,并 delegate 到底层 self.turtle.left(n)
。这涉及添加一些额外的方法,但避免了继承的所有陷阱。您可以创建
Turtle
实例并将它们传递给使它们以 C 风格命令式方式执行操作的函数,而不是类:def jump(turtle, height): ...
.
如果您计划创建某种相对频繁创建和销毁的粒子,并且您只需要一只乌龟来渲染而不是表示它们,您可以将粒子的内部表示和物理属性存储在一个类中,同时引用一个单“笔”龟。当需要绘制时,跟踪被禁用,乌龟在所有共享粒子中从一个位置移动到下一个位置,根据需要绘制。
理论上,这是一个很好的解决方案,但在实践中,我发现即使关闭跟踪器,它也会对性能产生太大影响。
自定义类可以从海龟的对象池中借用,有助于缓解垃圾收集问题。有关详细信息,请参阅为什么我的 Python Turtle 程序运行时间越长,速度会急剧下降?。
就是说,如果有人有的话,我很想看到一个有用的、不平凡的子类模式案例。