Python的重新模块 - 保存状态?

Eli*_*sky 12 python regex

我在Python中发现的最大烦恼之一是re模块无法在匹配对象中明确地保存其状态而无法保存其状态.通常,需要解析行,如果它们符合某个正则表达式,则从相同的正则表达式中取出它们的值.我想写这样的代码:

if re.match('foo (\w+) bar (\d+)', line):
  # do stuff with .group(1) and .group(2)
elif re.match('baz whoo_(\d+)', line):
  # do stuff with .group(1)
# etc.
Run Code Online (Sandbox Code Playgroud)

但遗憾的是,无法找到前一次调用的匹配对象re.match,所以这样写的如下:

m = re.match('foo (\w+) bar (\d+)', line)
if m:
  # do stuff with m.group(1) and m.group(2)
else:
  m = re.match('baz whoo_(\d+)', line)
  if m:
    # do stuff with m.group(1)
Run Code Online (Sandbox Code Playgroud)

随着elifs 的列表变长,这样不太方便并且变得非常笨拙.

一个hackish解决方案是将re.match和re.search包装在我自己的对象中,以保持状态.有没有人用过这个?您是否了解半标准实现(在大型框架或其他内容中)?

您还可以推荐哪些其他解决方法?或许,我只是在滥用模块,能够以更清洁的方式满足我的需求吗?

提前致谢

Cre*_*esh 5

您可能希望这个模块实现您正在寻找的包装器.


Aar*_*ron 4

尝试一些想法...

看来您理想地想要一个带有副作用的表达式。如果 Python 允许这样做:

if m = re.match('foo (\w+) bar (\d+)', line):
  # do stuff with m.group(1) and m.group(2)
elif m = re.match('baz whoo_(\d+)', line):
  # do stuff with m.group(1)
elif ...
Run Code Online (Sandbox Code Playgroud)

...那么您就可以清楚、干净地表达您的意图。但事实并非如此。如果嵌套函数中允许副作用,您可以:

m = None
def assign_m(x):
  m = x
  return x

if assign_m(re.match('foo (\w+) bar (\d+)', line)):
  # do stuff with m.group(1) and m.group(2)
elif assign_m(re.match('baz whoo_(\d+)', line)):
  # do stuff with m.group(1)
elif ...
Run Code Online (Sandbox Code Playgroud)

现在,这不仅变得丑陋,而且仍然不是有效的 Python 代码——不允许嵌套函数“assign_m”修改m外部作用域中的变量。我能想到的最好的办法真的很难看,使用允许副作用的嵌套类:

# per Brian's suggestion, a wrapper that is stateful
class m_(object):
  def match(self, *args):
    self.inner_ = re.match(*args)
    return self.inner_
  def group(self, *args):
    return self.inner_.group(*args)
m = m_()

# now 'm' is a stateful regex
if m.match('foo (\w+) bar (\d+)', line):
  # do stuff with m.group(1) and m.group(2)
elif m.match('baz whoo_(\d+)', line):
  # do stuff with m.group(1)
elif ...
Run Code Online (Sandbox Code Playgroud)

但这显然是多余的。

您可能会考虑使用内部函数来允许局部作用域退出,这允许您删除嵌套else

def find_the_right_match():
  # now 'm' is a stateful regex
  m = re.match('foo (\w+) bar (\d+)', line)
  if m:
    # do stuff with m.group(1) and m.group(2)
    return # <== exit nested function only
  m = re.match('baz whoo_(\d+)', line)
  if m:
    # do stuff with m.group(1)
    return

find_the_right_match()
Run Code Online (Sandbox Code Playgroud)

这可以让你将nesting=(2*N-1)展平为nesting=1,但你可能只是转移了副作用问题,并且嵌套函数很可能会让大多数Python程序员感到困惑。

最后,有一些无副作用的方法来处理这个问题:

def cond_with(*phrases):
  """for each 2-tuple, invokes first item.  the first pair where
  the first item returns logical true, result is passed to second
  function in pair.  Like an if-elif-elif.. chain"""
  for (cond_lambda, then_lambda) in phrases:
    c = cond_lambda()
    if c:
      return then_lambda(c) 
  return None


cond_with( 
  ((lambda: re.match('foo (\w+) bar (\d+)', line)), 
      (lambda m: 
          ... # do stuff with m.group(1) and m.group(2)
          )),
  ((lambda: re.match('baz whoo_(\d+)', line)),
      (lambda m:
          ... # do stuff with m.group(1)
          )),
  ...)
Run Code Online (Sandbox Code Playgroud)

现在代码看起来几乎不像 Python,更不用说 Python 程序员可以理解了(是 Lisp 吗?)。

我认为这个故事的寓意是 Python 没有针对这种习惯进行优化。您确实需要稍微冗长一些,并忍受其他条件的大量嵌套因素。