微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么这种使用 Python 中的 Turtle 模块检测按键的方法不起作用?

如何解决为什么这种使用 Python 中的 Turtle 模块检测按键的方法不起作用?

已阅读...

How can I log key presses using turtle?

我正在尝试使用稍微不同的方法检测按键。

这是我的代码的简化版本,它按预期工作...

from turtle import *

WIDTH,HEIGHT = 500,500
screen = Screen()
screen.setup(WIDTH,HEIGHT)
bgcolor('grey')
ht()
pu()
    
def checka():
    write('a')
    fd(10)
def checkb():
    write('b')
    fd(10)

screen.onkey(checka,'a')
screen.onkey(checkb,'b')

screen.listen()
screen.mainloop()

但是我希望处理所有字母的按键,所以尝试了这个...

from turtle import *

WIDTH,HEIGHT)
bgcolor('grey')
ht()
pu()
    
def check(l):
    write(l)
    fd(10)

screen.onkey(check('a'),'a')
screen.onkey(check('b'),'b')

screen.listen()
screen.mainloop()

但是这段代码不起作用。 任何人都可以对这里发生的事情有所了解,或者提出一种替代(但同样简单)的方法来实现相同的目标吗?

解决方法

我猜 screen.onkey() 需要一个它调用的函数。

您的代码:screen.onkey(check('a'),'a') 改为调用函数并返回 None,它不是函数。

您可以像这样使用 lambda 创建自己的函数:

screen.onkey(lambda :check('a'),'a')

如果您想为字母表中的每个字母调用 onkey(),那么您可以轻松地进行循环,但不会陷入 scope 问题:

import string

for c in string.ascii_lowercase:
    screen.onkey(lambda c=c:check(c),c)
,

screen.onkey() 函数需要一个函数作为输入。在您的第一个示例中,您正确执行此操作 (screen.onkey(checka,'a')),但在第二个示例中,您在传递它之前调用该函数 (screen.onkey(check('a'),'a')。这意味着您正在传递 返回值 check 函数,而不是函数本身。

您的检查函数中没有任何 return 语句明确返回值。在 Python 中,不显式返回值的函数返回 None。所以你实际上是在调用 screen.onkey(None,'a'),我猜这没有任何效果。

要解决此问题,您可以使用闭包 - 函数内的函数。使用闭包,内部函数可以使用外部函数可用的变量,这意味着您可以为任何字母创建检查函数。

def make_check_func(l):
    def check():
        write(l)
        fd(10)
    
    return check

screen.onkey(make_check_func('a'),'a')
screen.onkey(make_check_func('b'),'b')

或者,正如 quamrana 所建议的,您可以使用 lambda 函数以更少的代码完成同样的事情。

def check(l):
    write(l)
    fd(10)

screen.onkey(lambda: check('a'),'a')
screen.onkey(lambda: check('b'),'b')

--编辑--

要为字母表中的所有字母添加函数,您可以使用 for 循环。方便的是,Python 已经在 string.ascii_lowercase 处定义了一个包含所有小写 ASCII 字符的字符串,因此我们可以使用它来循环。

import string

def make_check_func(l):
    def check():
        write(l)
        fd(10)
    
    return check

for l in string.ascii_lowercase:
    screen.onkey(make_check_func(l),l)

这里,for 循环的主体将针对字符串中的每个字符运行一次,l 的值将是该字符。这具有运行 screen.onkey(make_check_func('a'),'a'),然后 screen.onkey(make_check_func('b'),'b'),一直到 screen.onkey(make_check_func('z'),'z') 的效果。

请注意,在 for 循环中使用 screen.onkey(lambda: check(l),l) 将不起作用,因为 lambda 函数“记住”的 l 的值将始终为“z”。有关说明,请参阅 common gotchas 条目。

,

虽然这可以使用@quamrana 演示的 lambda 解决,或者使用 @JackTaylor 详细解释的闭包来解决,但我偏爱 partial 解决此类问题:

from turtle import Screen,Turtle
from string import ascii_letters
from functools import partial

WIDTH,HEIGHT = 500,500

def check(letter):
    turtle.write(letter)
    turtle.forward(10)

screen = Screen()
screen.setup(WIDTH,HEIGHT)
screen.bgcolor('grey')

turtle = Turtle()
turtle.hideturtle()
turtle.penup()

for letter in ascii_letters:
    screen.onkey(partial(check,letter),letter)

screen.listen()
screen.mainloop()

partial 函数创建了一个新函数,其中原始函数的某些参数已被“锁定”。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。