1

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

can.coords 需要五个参数:您要“移动”的对象和新坐标。moveLeft() 和 addThirty() 的返回都是两个项目列表。当然,星号运算符(解包列表)不起作用。

如何将两个返回的函数列表中的四个项目传递给方法 .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()))))
4

3 回答 3

1

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

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

如果它们返回不同的类型(元组、列表、迭代器等),请执行以下操作:

args = list(moveLevt())
args.extend(addThirty(moveLeft()))
can.coords(oval1, *args)
于 2013-08-15T22:12:03.607 回答
1

您总是可以将两个列表或两个元组合并为一个,只需+

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)

在评论中,你说:

我不能这样做,因为我希望每次按下按钮时坐标都会改变。所以按钮需要: 执行这两个函数来修改坐标并一次性将它们传递给can.coords()。

仅仅把它放在一行中并不能做到这一点,甚至有助于使它更容易。您编写它的方式是调用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)

因为将它放在一行中的唯一方法是使用等效的lambdaor partial,这将比调用更不可读;就像是:

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本身。Butfoo()是一个表达式,其值通过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)......但是如果你想传递一个可以不带参数调用的函数并返回与返回相同的东西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 ......但是当 partial 在 Python 中不是微不足道的时候,不要尝试算了,写一个显式函数就行了。)

于 2013-08-15T22:15:31.140 回答
0

Sorry for digging up this topic, but after an interesting answer from a user on another topic, I thought I'll improve the answer to this question. Actually, you can assign a function with arguments to a command as long as it returns a function. In this case, it will avoid you a lot of trouble as you don't need to write a new function for every left right, down etc.

As you see, I can use arguments to the functions I assign to command:

command=move1(0,10)

I've written the code for only one oval, just to show how it works.

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()
于 2013-09-03T16:54:17.280 回答