Как передать переменную в обратный вызов re.sub? - PullRequest
4 голосов
/ 10 июля 2010

Я использую обратный вызов 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". Но я хочу иметь возможность выбирать значения случайным образом, и при этом они должны быть заменены в обеих строках. Это будет включать удаление строки 'mappings' в 'define' и использование чего-то вроде двух закомментированных строк. Однако как я могу получить мои случайно выбранные mappings2 для использования при оценке обеих строк, если я не могу передать его в качестве аргумента в функцию обратного вызова re.sub?

Большое спасибо.

Ответы [ 4 ]

12 голосов
/ 10 июля 2010

Я полагаю, что самый простой способ - использовать 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)
2 голосов
/ 10 июля 2010

Вы можете создать замыкание.

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 голос
/ 10 июля 2010

Вы можете использовать функциональный объект.

 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 голосов
/ 29 ноября 2013

Вариант, который я бы порекомендовал:

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() как локальную функцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...