Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python turtle/tkinter事件中的部分vs lambda_Python_Tkinter_Event Handling_Turtle Graphics - Fatal编程技术网

Python turtle/tkinter事件中的部分vs lambda

Python turtle/tkinter事件中的部分vs lambda,python,tkinter,event-handling,turtle-graphics,Python,Tkinter,Event Handling,Turtle Graphics,在Pythonturtle中,如果我想传递与事件系统指定的不同的事件处理程序参数,我可以使用lambda来弥合这一差异: from turtle import Screen, Turtle from functools import partial def change_color(color, x=None, y=None): screen.bgcolor(color) screen = Screen() screen.onclick(lambda x, y: change_co

在Pythonturtle中,如果我想传递与事件系统指定的不同的事件处理程序参数,我可以使用
lambda
来弥合这一差异:

from turtle import Screen, Turtle
from functools import partial

def change_color(color, x=None, y=None):
    screen.bgcolor(color)

screen = Screen()

screen.onclick(lambda x, y: change_color('blue'))

screen.mainloop()
或者我可以使用从functools导入的
partial
函数将
lambda
替换为:

screen.onclick(partial(change_color, 'blue'))
这很好。回到原始程序,我们可以用
ontimer()
事件替换
onclick()
事件,更新
lambda
,一切正常:

但是,当我们将此
lambda
替换为
部分时:

screen.ontimer(partial(change_color, 'blue'), 1000)
它会立即失败(不是在计时器启动时),原因是:

这很好用。我们还可以做到:

root.after(1000, lambda: change_color('blue'))
这很好用。但当我们这样做时:

root.after(1000, partial(change_color, 'blue'))
它再次出现故障,原因是:

回溯(最近一次呼叫最后一次):
文件“test.py”,第9行,在
根.after(1000,部分(更改颜色“蓝色”))
文件“/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/_init__.py”,第755行,后面
callit.\uuuuu name\uuuuu=func.\uuuuu name__
AttributeError:'functools.partial'对象没有属性'\uu\u名称''
>
partial
functools文档说明其返回值的行为类似于一个函数,但很明显,如果不是缺少的话,它是不同的。为什么呢?为什么tkinter/turtle接受
partial
函数作为单击事件处理程序,而不是计时器事件处理程序?

从中,它看起来像
functools。partial
不会从内部函数复制
\uuuu模块\uuuuu
属性。您可以通过手动定义
\uuuuu name\uuuu
来解决此问题:

import tkinter as tk
from functools import partial

def change_color(color):
    root.configure(bg=color)

root = tk.Tk()

c = partial(change_color, 'blue')
c.__name__ = "c"

root.after(1000, c)

root.mainloop()
为什么呢

它是这样设计的。 默认情况下,
partial
不带属性的压缩函数,但它们仍然可用:

partial_func = partial(change_color, 'blue')
print(partial_func.func.__name__)
应使用函数(或)显式设置正确的选项:

from turtle import Screen, Turtle
from functools import partial, update_wrapper

def change_color(color, x=None, y=None):
    screen.bgcolor(color)

def partial_change_color(color):
    partial_f = partial(change_color, color)
    update_wrapper(partial_f, change_color)

    return partial_f

screen = Screen()

screen.ontimer(partial_change_color('blue'), 1000)

screen.mainloop()
为什么tkinter/turtle接受部分函数作为点击事件处理程序,而不是计时器事件处理程序

同样,它是这样设计的。 因为绑定和调度算法在tkinter包装器中略有不同,而tkinter包装器

tkinter
创建额外的包装器
callit
,它使用
\uuuuu name\uuuuuuu
(因此,
AttributeError
)处理目标函数的非计划,而绑定。

我不需要解决方法——正如我所演示的
lambda
部分
失败时工作。根据您的回答,谢谢,我做了两件事:我为我的系统升级到了最新的Python;我搜索了有关此错误的旧报告。在当前的Python中,它似乎没有被修复,关于它的报告可以追溯到十多年前。我想我的第一个问题现在更像是,“为什么它仍然如此?”。我的第二个问题是,为什么它会影响一些tkinter事件处理程序,而不会影响其他事件处理程序,这个问题仍然没有答案。
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    root.after(1000, partial(change_color, 'blue'))
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 755, in after
    callit.__name__ = func.__name__
AttributeError: 'functools.partial' object has no attribute '__name__'
>
import tkinter as tk
from functools import partial

def change_color(color):
    root.configure(bg=color)

root = tk.Tk()

c = partial(change_color, 'blue')
c.__name__ = "c"

root.after(1000, c)

root.mainloop()
partial_func = partial(change_color, 'blue')
print(partial_func.func.__name__)
from turtle import Screen, Turtle
from functools import partial, update_wrapper

def change_color(color, x=None, y=None):
    screen.bgcolor(color)

def partial_change_color(color):
    partial_f = partial(change_color, color)
    update_wrapper(partial_f, change_color)

    return partial_f

screen = Screen()

screen.ontimer(partial_change_color('blue'), 1000)

screen.mainloop()