如何将变量传递给re.sub回调函数?

10

我正在使用re.sub回调函数将子字符串替换为随机值,但我希望不同的字符串之间的随机值是相同的。由于re.sub回调函数不允许参数,所以我不确定该如何实现。

这是我正在做的简化版本:

def evaluate(match):
    mappings = {'A': 1, 'B': 2}
    return str(eval(match.group(0)[2:-1], mappings))

# variables = {'A':[1,2,3,4,5], 'B':[1,2,3,4,5]}    
# mappings2 = {k:v[random.randint(0,len(v)-1)] for k, v in variables.items()}
string_one: "#{A} + #{B}"
string_two: "#{A+B}"
newstring_one = sub(r'\#\{([^#]+)\}', evaluate, string_one)
newstring_two = sub(r'\#\{([^#]+)\}', evaluate, string_two)

现在,字符串将被正确地评估:newstring_one 是"1 + 2",newstring_two 是"3"。但我希望能够随机选择值,并仍然使它们替换在两个字符串中。这将涉及删除'evaluate'中的 'mappings' 行,并使用类似于两行注释的内容。然而,如果我不能将随机选择的 mappings2 作为参数传递给 re.sub 回调函数,如何让它在评估两个字符串时被使用?

非常感谢。

4个回答

16
我想最简单的方法是利用functools.partial,它允许创建一个“部分求值”函数:
from functools import partial

def evaluate(match, mappings):
    return str(eval(match.group(0)[2:-1], mappings))

mappings = {'A': 1, 'B': 2}  # Or whatever ...

newstring = sub(r'\#\{([^#]+)\}', partial(evaluate, mappings=mappings), string)

只是一个提示:如果你颠倒 evaluate 参数的顺序,你可以简单地写成 partial(evaluate, mappings) - tzot
1
是的,但我有意使用参数顺序,因为我认为这种方式定义evaluate()更自然,并且我想展示partial()的灵活性。 - Ferdinand Beyer

2

您可以创建一个闭包。

def evaluator(mappings):
  def f(match):
    return str(eval(match.group(0)[2:-1], mappings))
  return f

evaluate = evaluator({'A': 1, 'B': 2})

由于f只是一个单一的语句,因此您可以直接使用lambda

def evaluator(mappings):
  return lambda match: str(eval(match.group(0)[2:-1], mappings))

1
你可以使用函数对象。
 class A(object):
  def __init__(self, mappings):
    self.mappings = mappings
  def __call__(self, match):
    return str(eval(match.group(0)[2:-1], self.mappings))

 evaluate = A({'A': 1, 'B': 2})

0

我推荐的变量是:

mappings = {'A': 1, 'B': 2}  # Or whatever ...
def evaluate(match):
    return str(eval(match.group(0)[2:-1], mappings))
newstring = sub(r'\#\{([^#]+)\}', evaluate, string)

即将def evaluate(..)放在sub()之前,作为一个局部函数。


1
你可以从预定义的变量中读取信息,但无法更改该变量。 - dolgom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接