在Python中传递函数作为方法参数返回

2024-09-29 21:52:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在编写一个小代码来在TkinterGUI中移动两个球,并做一些其他的事情。 我已经写了一段代码,但由于它使用了很多全局变量,我试图改进它。 下面我粘贴了与我的问题相关的代码部分:

你知道吗can.coords公司需要五个参数:要“移动”的对象和新的坐标。 moveLeft()和addthreen()返回的是两个项目列表。 当然,star操作符(打开列表)不起作用。你知道吗

如何将两个返回的函数列表中的四项传递到方法.coords()中?你知道吗

PS:我对Python甚至编程都是新手。你知道吗

def moveo (lr, tb):
    global newX, newY
    newX = x+lr
    newY = y+tb
    return newX, newY


def moveLeft ():
    coordins = moveo (-10, 0)
    return coordins

def addThirty (func):
    i = 0
    coordinsNew  = func
    coordinsNew = list(coordinsNew)
    while i < 2:
        coordinsNew[i] = coordinsNew[i]+30
        i += 1
    return coordinsNew

Button(wind, text = 'Left', command=can.coords (oval1,(*moveLeft()),(*addThirty(moveLeft()))))

Tags: 代码列表returndefcoordscantblr
3条回答

如果两个函数返回相同的类型(列表或元组),则只需执行以下操作:

can.coords(oval1, *(moveLeft() + addThirty(moveLeft())))

如果它们返回不同的类型(tuple、list、iterator等等),请执行以下操作:

args = list(moveLevt())
args.extend(addThirty(moveLeft()))
can.coords(oval1, *args)

抱歉,我把这个话题挖出来了,但是在一个用户对另一个话题做了一个有趣的回答之后,我想我会改进这个问题的答案。实际上,只要命令返回一个函数,就可以将带有参数的函数赋给它。在这种情况下,它将避免您很多麻烦,因为您不需要为每个左、右、下等写一个新函数

如您所见,我可以将参数用于分配给命令的函数:

command=move1(0,10)

我只为一个椭圆写了代码,只是为了展示它是如何工作的。你知道吗

from tkinter import *

x1, y1 = 135, 135
x2, y2 = 170, 170



def move1 (x, y):
    def moveo1 ():
        global x1, y1
        x1, y1 = x1+x, y1+y
        can.coords (oval1, x1, y1, x1+30, y1+30)
    return moveo1



##########MAIN############

wind = Tk()
wind.title ("Move Da Ball")

can = Canvas (wind, width = 300, height = 300, bg = "light blue")
can.pack (side = LEFT,padx = 5, pady = 5)


oval1 = can.create_oval(x1,y1,x1+30,y1+30,width=2,fill='orange') #Planet 1
Button(wind, text = 'Left', command=move1(-10,0)).pack(padx = 5, pady = 5)
Button(wind, text = 'Right', command=move1(10,0)).pack(padx = 5, pady = 5)
Button(wind, text = 'Top', command=move1(0,-10)).pack(padx = 5, pady = 5)
Button(wind, text = 'Bottom', command=move1(0,10)).pack(padx = 5, pady = 5)


Button(wind, text = 'Quit', command=wind.destroy).pack(padx = 5, pady = 5)

wind.mainloop()

只需使用+即可将两个列表或两个元组组合成一个:

can.coords(oval1, *(moveLeft() + addThirty(moveLeft())))

即使您有不同类型的序列(甚至迭代器),也可以始终转换它们:

can.coords(oval1, *(moveLeft() + tuple(addThirty(moveLeft())))))

然而,你真的应该退一步,问为什么这需要一行放在首位。它从屏幕的右边缘滚动,需要足够复杂的括号,您必须仔细考虑才能理解它,等等。为什么不这样做:

top, left = moveLeft()
bottom, right = addThirty(moveLeft())
can.coords(oval1, top, left, bottom, right)

你在评论中说:

I can't do this because I want the coordinates to change every time I press the button. So the button needs to : execute both functions to modify the coordinates and pass them to can.coords () in one time.

仅仅把它放在一行是做不到的,甚至有助于使这更容易。按照编写的方式,调用can.coords一次,并将结果返回值作为命令传递。那不是你想要的。您需要传递的是一个函数,它完成所有这些事情。你知道吗

这意味着你肯定想把它分成多行。例如:

def update_coords():
    top, left = moveLeft()
    bottom, right = addThirty(moveLeft())
    can.coords(oval1, top, left, bottom, right)
Button(wind, text = 'Left', command=update_coords)

因为把它放在一行的唯一方法是用一个等价的lambdapartial,它甚至比一个调用更不可读;比如:

Button(wind, text = 'Left', command=lambda: can.coords(oval1, *(moveLeft() + addThirty(moveLeft()))))

为了解释传递函数与调用函数及其返回值之间的区别,让我们举一个更简单的例子:

>>> def foo():
...     return 2
>>> print(foo)
<function foo at 0x12345678>
>>> print(foo())
2

在这里,应该很清楚区别是什么。foo是一个表达式,其值是函数foo本身。但是foo()是一个表达式,它的值是通过调用不带参数的foo,然后使用返回的内容(在本例中为2)来确定的。你知道吗

如果我们把事情弄复杂一点,也没什么不同:

>>> def bar(x, y):
...     return x+y
>>> print(bar)
<function bar at 0x12345680>
>>> print(bar(2, 3))
6

所以,很明显,你可以传递bar本身,或者你可以传递6你从bar(2, 3)得到的6…但是如果你想传递一个可以不带参数调用的函数,并返回bar(2, 3)将返回的相同的东西呢?好吧,你没有这样的东西,你必须创造它。你知道吗

您可以通过两种方式完成此操作:创建新函数:

>>> def new_function():
...     return bar(2, 3)

…或部分评估功能:

>>> new_function = partial(bar, 2, 3)

您的案例增加了一些额外的麻烦:您是从绑定方法而不是函数开始的,您需要确保每次运行新函数时都对参数进行求值(因为每次调用moveLeft()两次而不是仅仅调用一次与每次调用can.coords一样重要),并且您有一堆你的处境很复杂。但这些皱纹都不会让事情变得更困难,你只要看看过去:

>>> def new_function():
...     can.coords(oval1, *(moveLeft() + addThirty(moveLeft())))

(编写partial要困难得多,因为您必须将一系列函数组合在一起才能得到参数,您也需要对这些参数进行partial…但是在Python中,只要partial不是无关紧要的事情,就不要试图弄清楚,只需编写一个显式函数即可。)

相关问题 更多 >

    热门问题