【问题标题】:Python: is there a way to use "unimported" objects in function definitions?Python:有没有办法在函数定义中使用“未导入”对象?
【发布时间】:2015-08-18 07:25:17
【问题描述】:

我正在修改一个简单的递归函数来使用turtle绘制一条龙曲线:

def draw_dragon(t, order, size, L=turtle.left, R=turtle.right):
    """ Draw a dragon curve """
    if not order:
        t.forward(size)
        return

    size /= 1.41421
    t.R(45)
    draw_dragon(t, order-1, size, L, R)
    t.L(90)
    draw_dragon(t, order-1, size, R, L)
    t.R(45)

if __name__=="__main__":
    import turtle
    wn = turtle.Screen()
    fred=turtle.Turtle()
    draw_dragon(fred,6,200)
    wn.exitonclick()

由于我在函数定义的时候还没有导入turtle,解释器给了我"NameError: name 'turtle' is not defined"

有没有办法在我的 draw_dragon 函数中仍然使用 turtle 模块的函数,而无需先将它们导入函数之外?

【问题讨论】:

  • 这是什么原因?当您定义draw_dragon 时,您将turtle.left 分配给L kwarg;如果您不告诉解释器(通过import 语句或定义),解释器怎么会知道您要分配给L 的内容。解释器解析turtle.arg(它很聪明,可以通过. 拆分违规值,从而告诉您第一个未找到的子模块是什么)
  • “因为我在函数定义的时候还没有导入turtle”——好吧,为什么不呢?
  • “有没有办法”?可以说,有一些非常可怕的黑客。有没有一种的方法,符合最佳实践,也不会破坏编辑器的代码分析?不。(为什么你想要一个,而不是仅仅将import 移动到文件的顶部?)
  • 我在想,万一你一开始就导入了命名空间,后来你可能会遇到命名空间冲突(你不能“取消导入”命名空间吗?)我还想Python 只是跳过函数定义,直到调用/执行函数时才需要命名空间......
  • 实际上可以,但您不应使用与您正在使用的模块相同的名称。

标签: python function namespaces python-module


【解决方案1】:

在定义函数之前没有导入的原因是什么?
我不确定你为什么需要将导入放在 main 函数中。

我不相信函数有什么神奇的方法可以知道turtle的模块是什么,除非它们是a)在命名空间中,或者b)通过参数传递给函数。你可以把它放在你的主代码中:

if __name__=="__main__":
    import turtle
    wn = turtle.Screen()
    fred=turtle.Turtle()
    draw_dragon(fred,6,200,turtle.left, turtle.right)
    wn.exitonclick()          ^^^            ^^^

然后,将 L 和 R 更改为没有默认参数(它们将通过初始调用分配函数),这样您就不会得到 NameErrors。

您的函数现在应该知道方法是什么,因为您通过 main 将它们传递给函数。

不过,您可能应该将导入调用移到脚本的开头!

编辑:

您的代码仍然有一些奇怪的特质。与其尝试将导入模块中的方法传递给您的函数,不如使用您创建的海龟对象中的函数!这段代码应该可以工作,但这绝对不是您想要使用的常见做法......

def draw_dragon(t, order, size, right, left, forward):
    """ Draw a dragon curve """
    if order <= 0:
        forward(size)
        return

    size /= 1.41421
    right(45)
    draw_dragon(t, order-1, size, right, left, forward)
    left(90)
    draw_dragon(t, order-1, size, left, right, forward)
    right(45)

if __name__=="__main__":
    import turtle
    wn = turtle.Screen()
    fred=turtle.Turtle()
    draw_dragon(fred, 6,200, turtle.left, turtle.right, turtle.forward)
    wn.exitonclick()

更好的代码是这样的:

from turtle import Screen, left, right, forward, speed, hideturtle

def draw_dragon(order, size, left, right):
    """ Draw a dragon curve """
    if order <= 0:
        forward(size)
        return
    size /= 1.41421
    right(45)
    draw_dragon(order-1, size, right, left)
    left(90)
    draw_dragon(order-1, size, left, right)
    right(45)

if __name__=="__main__":
    speed(0)
    hideturtle()
    wn = Screen()
    draw_dragon(8,200, left, right)
    wn.exitonclick()

【讨论】:

  • 谢谢——我将 L 和 R 更改为没有默认参数,并将海龟函数传递给 draw_dragon。这次我不再收到 NameError 而是收到 AttributeError: 'Turtle' object has no attribute 'R'...然后我完全摆脱了 turtle 't' 参数并且脚本开始工作 - 为什么会这样?
  • "t" 是指海龟对象。如果您使用我的旧编辑之一,R 现在是“turtle.right” 当您调用 t.R 时,您说的是“turtle.turtle.right”,这当然不是函数! R 已经是“turtle.right”,所以你可以做 R(angle)。
  • 最后一个菜鸟问题:为什么您不再需要 Screen、Turtle 和其他设置的实例才能使新版本工作? (我想这与from xmodule import yfunc 有关?再次感谢 :)
  • 你仍然有 Screen 的实例(这是 Turtle 知道要绘制的地方)。我在 Turtle 方面的经验并不丰富,但我相信 Screen 是 Turtle 方法(左、右、前向等)知道可以对其进行操作的单例。文档可能有更多关于为什么它与龟一起工作的细节(docs.python.org/3.4/library/turtle.html),但总的来说,它取决于您导入的方法的具体实现。
【解决方案2】:

我认为问题可能是由于您的 turtle.py 不在 sys.path 中的目录中。

【讨论】:

  • 我认为你错了;)这将导致ImportError,而不是NameError。问题是,由于 OP 正在导入 turtle after 函数的定义(它引用 turtle fo 参数的默认值),当 def 语句为时,名称 turtle 不存在评估。
  • 我以为我在函数被评估之前导入了海龟......所以在评估(而不是定义)函数时,海龟不应该已经可见吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 2023-02-15
  • 2019-04-20
  • 1970-01-01
相关资源
最近更新 更多