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

10 投票
4 回答
5765 浏览
提问于 2025-04-16 01:05

我正在使用一个叫做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 个回答

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})
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))
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)

撰写回答