Turtle Library Python:如果 Screen 不是一个类,当我执行 screen = Screen() 时我在做什么?

问题描述 投票:0回答:1

我正在学习 Udemy for Python 上的 Angela Yu 博士的“100 天编程”课程。我在第 22 天使用 Turtle 重新创建 Pong 游戏。

我认为 Screen() 是一个类,因为我一直像 Turtle() 一样对待它并像这样编码:

 from turtle import Turtle, Screen

 tort = Turtle()

 display = Screen()
 display.bgcolor("orange")
 display.exitonclick()

但是每当我开始在 pycharm 社区中输入 Screen() 时,在弹出的下拉菜单中,“Screen()”旁边有一个小红圈“f”。相反,当我开始输入“Turtle() 或“Turtle”时,它旁边有一个小蓝色圆圈“c”。

circled red f symbol next to Screen in popup circled red f symbol next to Screen in popup

这是否意味着 Screen() 绝对不是一个类?如果是这样,为什么我可以使用 Screen() 创建一个对象,就像使用 Turtle() 一样?

并不是我的代码不起作用,我只是不明白为什么它会这样工作。

另外,我还意识到我可以通过这样编写代码来完成同样的事情: 从海龟进口海龟

 tort = Turtle()

 tort.screen.bgcolor("orange")
 tort.screen.exitonclick()

但是 pycharm 黄色强调了“exitonclick()”部分,其中包含“类‘TurtleScreen’的未解析属性引用‘exitonclick’”,这只会让我更加困惑,因为……那么为什么当我运行它时它工作得很好。

python oop turtle-graphics
1个回答
0
投票

序言:turtle 是一团糟,而且对初学者来说并不那么友好。 API 中存在大量不一致之处,它几乎打破了 Zen of Python 的每条规则。可能就是这样,因为它是很久以前写的,并且从那以后就没有太大改变。因此,当海龟 API 或内部结构的某些部分莫名其妙地奇怪或不一致或 IDE 自动完成变得混乱时,请不要太惊讶。


查看

turtle.py
中CPython的源代码:

def Screen():
    """Return the singleton screen object.
    If none exists at the moment, create a new one and return it,
    else return the existing one."""
    if Turtle._screen is None:
        Turtle._screen = _Screen()
    return Turtle._screen

Screen()
是一个函数,只是命名方式打破了PEP-8 Python风格指南,该指南指定函数应该是
lower_snake_case
类应该是
UpperPascalCase
。分歧的基本原理可能是它是一个单例实例,因此它返回现有的
_Screen
或创建一个新实例(如果不存在)。

另一方面,

Turtle
显然是一个类:

class Turtle(RawTurtle):
    """RawTurtle auto-creating (scrolled) canvas.

    When a Turtle object is created or a function derived from some
    Turtle method is called a TurtleScreen object is automatically created.
    """
    _pen = None
    _screen = None

    def __init__(self,
                 shape=_CFG["shape"],
                 undobuffersize=_CFG["undobuffersize"],
                 visible=_CFG["visible"]):
        if Turtle._screen is None:
            Turtle._screen = Screen()
        RawTurtle.__init__(self, Turtle._screen,
                           shape=shape,
                           undobuffersize=undobuffersize,
                           visible=visible)
    # ...

关于你的第二个问题,

exitonclick
文档字符串中有一条评论:

这是

Screen
类的方法,不适用于
TurtleScreen
实例。

注释的原因是它位于继承自

_Screen
的类
TurtleScreen
中。当您创建
Turtle()
并且不指定屏幕时,将调用上面显示的
def Screen
函数,创建一个
_Screen
实例。评论看起来不正确,实际上应该说
_Screen
类。

因此

exitonclick
方法将在运行时可供您的实例使用,但到达那里的路径存在 IDE 无法静态解析的条件,例如:

class RawTurtle(TPen, TNavigator):
    """Animation part of the RawTurtle.
    Puts RawTurtle upon a TurtleScreen and provides tools for
    its animation.
    """
    screens = []

    def __init__(self, canvas=None,
                 shape=_CFG["shape"],
                 undobuffersize=_CFG["undobuffersize"],
                 visible=_CFG["visible"]):
        if isinstance(canvas, _Screen): # this branch will be taken in OP's case
            self.screen = canvas
        elif isinstance(canvas, TurtleScreen):
            if canvas not in RawTurtle.screens:
                RawTurtle.screens.append(canvas)
            self.screen = canvas
        elif isinstance(canvas, (ScrolledCanvas, Canvas)):
            for screen in RawTurtle.screens:
                if screen.cv == canvas:
                    self.screen = screen
                    break
            else:
                self.screen = TurtleScreen(canvas)
                RawTurtle.screens.append(self.screen)
        else:
            raise TurtleGraphicsError("bad canvas argument %s" % canvas)

一般来说,Turtle 使用运行时元编程来动态连接各处的一堆冗余类和属性。如果其中一些自动连接使 IDE 感到困惑,我不会感到惊讶。

© www.soinside.com 2019 - 2024. All rights reserved.