将可选函数(和可选参数)传递给Python中的另一个函数?

时间:2018-03-31 00:47:58

标签: python python-3.x typeerror args

我是学习Python的新手,并且有足够的资源开始尝试初学者的Tic-Tac-Toe计划。

我的问题是:我希望有一个名为getInput()的通用输入函数,它将从用户获取输入,从该输入中去除尾随空格,然后,如果函数通过可选参数传递给它,那么" specialTest",getInput()将通过此提供的函数运行输入,并返回specialTest函数吐出的输出。

有时这个specialTest函数除了用户输入之外还需要额外的参数。假设我的目的是用户输入将始终是第一个参数并且是必需的,并且之后会出现任何其他参数。

我尝试通过* args实现这种情况,如果specialTest函数没有其他参数,我就可以使用它。但是,当我第一次尝试提供额外的参数时,它就失败了。

例如, getInput(" Age?",specialTest = int)有效。它提示用户输入并通过int()函数提供它,最后将输出作为整数返回。但是当我尝试传递一个带有附加参数的函数getInput()时 - 一个包含字符串作为键和字典作为值的有序字典 - 程序失败, TypeTypeError:getInput()得到多个参数值#39 ; specialTest' 即可。需要调整什么才能使其按预期工作?

代码:

import collections


def getInput(msg, specialTest=None, *TestArgs):
    """Get user input and export to the desired format."""
    while True:
        string = input(msg + ' ').strip()

        # If the user passed a function to the SpecialTest parameter,
        # pass the user input through that function and return its value.
        # If the SpecialTest function returns False or we hit an error,
        # that means the input was invalid and we need to keep looping
        # until we get valid input.
        if specialTest:
            try:
                string = specialTest(string, *TestArgs)
                if string is False: continue
            except:
                continue

        return string


def nametoMove(name, board):
    """Convert player's move to an equivalent board location."""
    location = {name: theBoard.get(name)}
    # return false if the location name isn't present on the board
    if location[name] is None:
        return False
    return location


# ---Tic-Tac-Toe routine---

# fill the board
row_name = ('top', 'mid', 'lower')
col_name = ('left', 'center', 'right')

theBoard = collections.OrderedDict()
size = 3  # 3x3 board

for x in range(size):
    for y in range(size):
        key = row_name[x] + ' ' + col_name[y]
        value = {'row': x, 'col': y}
        theBoard.update({key: value})

# get player's desired board symbol
playerSymbol = getInput("X's or O's?")

# get player's age
playerAge = getInput("Age?", specialTest=int)

# get player's move and convert to same format as theBoard object
# e.g., "top left" --> {'top left': {'row': 0, 'col': 0}}
playerMove = getInput("Move?", specialTest=nametoMove, *theBoard)

1 个答案:

答案 0 :(得分:1)

为了支持通过位置或关键字参数提供相同的参数,Python converts any keyword arguments that can be为位置参数。这会在你的例子中产生冲突。从语法上讲,你可以通过简单地省略参数来实现你想要的东西:

playerMove = getInput("Move?", nametoMove, *theBoard)

或者您可以使用“仅限关键字”参数解决歧义:

def getInput(msg, *TestArgs , specialTest=None):

然后无法转换关键字参数,因此没有冲突。 (这可以在Python 2中使用**kw来接受任意关键字参数,然后检查是否只实际提供了预期的参数。)

应该提出的问题是“如何为一个用作回调的函数预设一些参数?”,答案是lambda

playerMove = getInput("Move?", specialTest=lambda s: nametoMove(s, *theBoard))

functools.partial

playerMove = getInput("Move?", specialTest=functools.partial(nametoMove, board=theBoard))

使用其中任何一个,您根本不需要TestArgspartial方法不支持提供尾随位置参数(如varargs),但您的nametoMove实际上并不想要那些(如评论中所述)。因此,在上述所有方法中,您省略了*