在Python中创建动态部分可调用对象
我在 YAML 配置文件中定义了一个正则表达式。
为了方便起见,我将在这里使用字典:
rule_1 = {
'kind': 'regex',
'method': 'match',
'args': None,
'kwargs': {
'pattern': "[a-z_]+",
'flags': re.X,
'string': 's_test.log',
}
}
我希望能够在函数中解析该规则。
如果我们假设这些值不会改变,那么我可以做这样的事情。
导入模块:
import re
from operator import methodcaller
from functools import partial
我下面的第一个函数能够适应所使用的正则表达式方法的变化:
def rule_parser_re_1(*, kind, method, args=None, kwargs=None):
if args is None: args = []
if kwargs is None: kwargs = {}
mc = methodcaller(method, **kwargs)
return mc(re)
它按预期工作:
>>> rule_parser_re_1(**rule_1)
<re.Match object; span=(0, 6), match='s_test'>
现在,假设在定义配置字典时我没有要解析的字符串。
例如,假设它是文件中的特定行,只能在运行时访问。
myfile = """
first line
second line
third line
"""
io_myfile = io.StringIO(myfile)
content = io_myfile.readlines()
我的第二条规则,其中“line_number”(即 an int)替换“string”(即 a str)。
rule_2 = {
'kind': 'regex',
'method': 'match',
'args': None,
'kwargs': {
'pattern': "[a-z_]+",
'flags': re.X,
'line_number': 2,
}
}
我的理解是我应该能够通过定义一个偏rule_parser_re函数来解决这个问题。这样的函数应该像原来的函数一样使用patternand调用flags,但不使用string。
我想出了以下功能:
def rule_parser_re_2(*, kind, method, args=None, kwargs=None):
if args is None: args = []
if kwargs is None: kwargs = {}
if kind == 'regex' and method == 'match':
pa = partial(re.match, pattern=kwargs['pattern'], flags=kwargs['flags'])
return pa
这似乎也可以正常工作:
>>> r2 = rule_parser_re_2(**rule_2)
>>> r2(string=content[2])
<re.Match object; span=(0, 6), match='second'>
虽然,我看到上述实现有两个可维护性问题:
- 我正在使用该
if语句,它迫使我为re我想要支持的每个方法修改函数; - 我需要明确指定参数,而不仅仅是解压“**kwargs”
我的目标/怀疑:
- 有什么办法可以使上述功能更加动态和可维护吗?
- 是
functools.partial()和operator.methodcaller()对工作的合适的工具? - 如果可以,它们可以组合在一起吗?
谢谢!