将可选函数(和可选参数)传递给 Python 中的另一个函数?
Passing an optional function (and optional parameters) to another function in Python?
我刚开始学习 Python 并且我有足够的能力开始尝试初学者的 Tic-Tac-Toe 程序。
因此我的问题是:我想要一个名为 getInput() 的通用输入函数,它将从用户那里获取输入,从该输入中去除尾随的白色 space,然后,如果传递了一个函数通过可选参数 "specialTest",getInput() 将 运行 通过此提供的函数输入,return specialTest 函数吐出的输出。
有时这个 specialTest 函数除了用户输入之外还需要额外的参数。出于我的目的,假设用户输入将始终是第一个参数并且是必需的,并且之后会出现任何其他参数。
我尝试通过 *args 实现这种情况,如果 specialTest 函数没有额外的参数,我就可以正常工作。但是我第一次尝试向它提供额外的参数时,它失败了。
例如,getInput("Age?", specialTest=int) 有效。它提示用户输入并通过 int() 函数提供输入,最后 return 将输出作为整数。但是当我尝试传递 getInput() 一个函数时,它有一个额外的参数 - 一个包含字符串作为键和字典作为值的有序字典 - 程序失败并出现 TypeTypeError: getInput() got multiple values for argument '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)
为了支持通过位置参数或关键字参数提供相同的参数,Python converts any keyword arguments that can be 到位置参数。这会在您的示例中造成冲突。从句法上讲,你想要的可以通过简单地省略参数来实现:
playerMove = getInput("Move?", nametoMove, *theBoard)
或者你可以用“keyword-only”参数来解决歧义:
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))
使用其中任何一个,您根本不需要 TestArgs
。 partial
方法不支持提供 trailing 位置参数(如 varargs),但你的 nametoMove
实际上并不需要那些(如评论中所述) ).所以在上面的所有方法中你都省略了 *
.
我刚开始学习 Python 并且我有足够的能力开始尝试初学者的 Tic-Tac-Toe 程序。
因此我的问题是:我想要一个名为 getInput() 的通用输入函数,它将从用户那里获取输入,从该输入中去除尾随的白色 space,然后,如果传递了一个函数通过可选参数 "specialTest",getInput() 将 运行 通过此提供的函数输入,return specialTest 函数吐出的输出。
有时这个 specialTest 函数除了用户输入之外还需要额外的参数。出于我的目的,假设用户输入将始终是第一个参数并且是必需的,并且之后会出现任何其他参数。
我尝试通过 *args 实现这种情况,如果 specialTest 函数没有额外的参数,我就可以正常工作。但是我第一次尝试向它提供额外的参数时,它失败了。
例如,getInput("Age?", specialTest=int) 有效。它提示用户输入并通过 int() 函数提供输入,最后 return 将输出作为整数。但是当我尝试传递 getInput() 一个函数时,它有一个额外的参数 - 一个包含字符串作为键和字典作为值的有序字典 - 程序失败并出现 TypeTypeError: getInput() got multiple values for argument '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)
为了支持通过位置参数或关键字参数提供相同的参数,Python converts any keyword arguments that can be 到位置参数。这会在您的示例中造成冲突。从句法上讲,你想要的可以通过简单地省略参数来实现:
playerMove = getInput("Move?", nametoMove, *theBoard)
或者你可以用“keyword-only”参数来解决歧义:
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))
使用其中任何一个,您根本不需要 TestArgs
。 partial
方法不支持提供 trailing 位置参数(如 varargs),但你的 nametoMove
实际上并不需要那些(如评论中所述) ).所以在上面的所有方法中你都省略了 *
.