Python中函数参数的模式匹配
假设我有一个名为Python中函数参数的模式匹配,python,function,python-3.x,pattern-matching,parameter-passing,Python,Function,Python 3.x,Pattern Matching,Parameter Passing,假设我有一个名为generator的函数,它返回一个4元组,其中包含在某些预先指定的范围内随机选择的值。假设元组的形式为(年龄、性别、位置、婚姻状况): 另一方面,假设我定义了20个不同的函数,定义如下: def p1 (age, sex, location, marital_status) def p2 (age, sex, location, marital_status) . . # This function has a foratted doc string. # :argum
generator
的函数,它返回一个4元组,其中包含在某些预先指定的范围内随机选择的值。假设元组的形式为(年龄、性别、位置、婚姻状况)
:
另一方面,假设我定义了20个不同的函数,定义如下:
def p1 (age, sex, location, marital_status)
def p2 (age, sex, location, marital_status)
.
.
# This function has a foratted doc string.
# :argument: Truth condition to be evaluated
# If any condition is False, function won't be called
def party_list(name, age, sex):
"""
:name:"{}" != "Dad"
:age:17< {} <25
:sex:True
"""
print("You're invited to my party, {}!".format(name))
# We will make some sample data
keys = ["name", "age", "sex"]
values = [["John", 24, "Male"],
["Sarah", 25, "Female"],
["Pikachu", 2, "Pokemon"],
["Pizza guy", 18, "Male"]]
# Turn it in to a dictionary
for key, value in enumerate(values):
values[key] = {t:p for t, p in zip(keys, value)}
# These conditions can be dynamically made for each function,
# because we have access to the doc string from the outside
conditions = list(filter(lambda c: ':' in c, party_list.__doc__.split('\n')))
for friend in values:
for case in conditions:
tag, code = case.split(':')[1:]
if not eval(code.format(friend[tag])):
break
else:
party_list(friend["name"], friend["age"], friend["sex"])
其中,p1
应接收具有以下形式值的参数:
`age` must be in the range 20 to 45
`sex` must be male
`location` could be any city in Southern California
`marital_status` could be either single or married
想象一下从p2
一直到p20
的另一组值
确定哪一组生成的值与哪一个函数匹配的实用方法是什么
在这种情况下,所有定义都完全相同,但我可以想象在定义中可能存在细微差异的情况,例如p18
可能是def p1(年龄、位置)
,并且age
和location
的可能性范围有特定限制
另外,模式不一定是相互排斥的,这意味着一组生成的值也可能匹配多个函数
# define test t1 for function p1
def t1(params):
return params["age"] in range(5, 85) \
and params["sex"] in ["m", "f"] \
and cityof(params["location"], "California") \
and params["marital_status"] in ["married", "single", "separated"]
# and similarly for other p* functions
# define functions
def p1(params): ...
def p2(params): ...
# and so on
# bind tests and functions
RULES = {
(t1, p1),
(t2, p2),
...
}
# have the right functions called
def go(params):
for rule in RULES:
if rule[0](params):
rule[1](params)
# test it
go({"age": 6, "sex": "m", "location": "somewhere", "marital_status": "single"})
仅作几点评论:
- 这些测试可以包含在函数本身中
- 测试功能也必须处理缺失的参数
- 也可以直接使用函数参数
找到匹配函数并调用它。 如果您愿意在您的函数中添加格式化的DOC字符串(而不是对每个参数进行类型检查),那么您可以考虑这样做:
def p1 (age, sex, location, marital_status)
def p2 (age, sex, location, marital_status)
.
.
# This function has a foratted doc string.
# :argument: Truth condition to be evaluated
# If any condition is False, function won't be called
def party_list(name, age, sex):
"""
:name:"{}" != "Dad"
:age:17< {} <25
:sex:True
"""
print("You're invited to my party, {}!".format(name))
# We will make some sample data
keys = ["name", "age", "sex"]
values = [["John", 24, "Male"],
["Sarah", 25, "Female"],
["Pikachu", 2, "Pokemon"],
["Pizza guy", 18, "Male"]]
# Turn it in to a dictionary
for key, value in enumerate(values):
values[key] = {t:p for t, p in zip(keys, value)}
# These conditions can be dynamically made for each function,
# because we have access to the doc string from the outside
conditions = list(filter(lambda c: ':' in c, party_list.__doc__.split('\n')))
for friend in values:
for case in conditions:
tag, code = case.split(':')[1:]
if not eval(code.format(friend[tag])):
break
else:
party_list(friend["name"], friend["age"], friend["sex"])
#此函数有一个带孔的文档字符串。
#:参数:要计算的真值条件
#若任何条件为False,则不会调用该函数
def party_列表(姓名、年龄、性别):
"""
:姓名:“{}”!=“爸爸”
:age:17<{}作为Python 3.X(而不是2.X)中的一种Python方式,您可以将(关于函数参数和结果的任意用户定义数据)附加到函数对象。在这里,您可以在装饰器中使用此功能包装函数以检查参数的范围
例如,您可以使用以下范围测试功能:
def rangetest(func):
def onCall(**kargs):
argchecks = func.__annotations__
if all(val in range(*argchecks.get(arg)) for arg,val in kargs.items()):
return func(**kargs)
else :
print ("invalid arg range")
return onCall
@rangetest
def func(a:(1, 5), b:(4,7), c:(0, 10)):
print(a + b + c)
演示:
func(a=2, b=6, c=8)
16
func(a=2, b=6, c=15)
invalid arg range
首先,由于注释信息在字典中(python将其作为字典返回),并且字典没有特定的顺序,因此需要在函数中使用关键字参数,以便能够在注释信息字典中获取其相对范围
在这里,我只使用了数字范围,但您可以使用一些自定义范围,如您在问题中显示的单词列表。但在all
中,您需要检查其类型,然后根据其类型使用正确的操作:
all(kwargs.get(arg) in range(*arg_range) if is instance (arg_range,tuple) else kwargs.get(arg) in arg_range for arg,arg_range in argchecks.items())
由于您使用的是Python 3,函数注释可能是一种方法:。模式是相互排斥的,还是可能有更多的模式匹配?@dlask:这一点很好。模式匹配多个函数的可能性很小。是否可以在p1-p20上循环,检查函数本身,如果与reqs不匹配,直接转到下一个函数?避免代码重复。@JLPeyret:听起来很有趣。您能详细说明一下答案吗?