pythonic方法在if语句中重写赋值

时间:2010-09-19 03:09:10

标签: python syntax if-statement

我是否会采用pythonic首选方式执行此操作:


for s in str:
    if r = regex.match(s):
        print r.groups()

我非常喜欢这种语法,因为它比在任何地方都有临时变量要清晰得多。唯一不太复杂的其他方式是


for s in str:
    r = regex.match(s)
    if r:
        print r.groups()

我想我抱怨一个非常迂腐的问题。我只是想念以前的语法。

7 个答案:

答案 0 :(得分:10)

怎么样

for r in [regex.match(s) for s in str]:
    if r:
        print r.groups()

或更具功能性

for r in filter(None, map(regex.match, str)):
    print r.groups()

答案 1 :(得分:2)

也许它有点hacky,但使用函数对象的属性来存储最后的结果可以让你沿着这些方面做点什么:

def fn(regex, s):
    fn.match = regex.match(s) # save result
    return fn.match

for s in strings:
    if fn(regex, s):
        print fn.match.groups()

或者更一般地说:

def cache(value):
    cache.value = value
    return value

for s in strings:
    if cache(regex.match(s)):
        print cache.value.groups()

请注意,尽管保存的“值”可以是许多内容的集合,但此方法仅限于一次只保留一个,因此可能需要多个函数来处理多个值需要的情况同时保存,例如嵌套函数调用,循环或其他线程。因此,根据DRY原则,工厂函数可以提供帮助,而不是编写每个原则。

def Cache():
    def cache(value):
        cache.value = value
        return value
    return cache

cache1 = Cache()
for s in strings:
    if cache1(regex.match(s)):
        # use another at same time
        cache2 = Cache()
        if cache2(somethingelse) != cache1.value:
            process(cache2.value)
        print cache1.value.groups()
          ...

答案 2 :(得分:1)

有一个recipe来制作一个赋值表达式,但它非常hacky。你的第一个选项没有编译,所以你的第二个选择是要走的路。

## {{{ http://code.activestate.com/recipes/202234/ (r2)
import sys
def set(**kw):
    assert len(kw)==1

    a = sys._getframe(1)
    a.f_locals.update(kw)
    return kw.values()[0]

#
# sample
#

A=range(10)

while set(x=A.pop()):
    print x
## end of http://code.activestate.com/recipes/202234/ }}}

正如你所看到的,生产代码不应该用十英尺双袋装棒来触摸这个黑客。

答案 3 :(得分:1)

这可能是一个过于简单的答案,但你会考虑这个:

for s in str:
    if regex.match(s):
        print regex.match(s).groups()

答案 4 :(得分:1)

没有pythonic方式来做一些不是pythonic的事情。这是出于某种原因,因为1,允许if语句的条件部分中的语句会使语法变得非常难看,例如,如果你在if条件中允许赋值语句,为什么不允许if语句呢?你怎么写这个? C语言没有这个问题,因为它们没有赋值语句。他们只使用赋值表达式和表达式语句。

第二个原因是因为

的方式
if foo = bar:
    pass

非常相似
if foo == bar:
    pass

即使你足够聪明地键入正确的那个,即使你团队中的大多数成员都足够清楚地注意到它,你确定你现在正在看的那个正是应该是什么那里?一个新的开发人员看到这个并且只是修复它(这种或那种方式)并不是没有道理的,现在它肯定是错误的。

答案 5 :(得分:1)

每当我发现我的循环逻辑变得复杂时,我会按照其他任何逻辑做我想做的事情:我将它提取到函数中。在Python中,干净利落地比其他语言容易得多。

因此,提取仅生成感兴趣项目的代码:

def matching(strings, regex):
    for s in strings:
        r = regex.match(s)
        if r: yield r

然后当你想要使用它时,循环本身就像它们一样简单:

for r in matching(strings, regex):
    print r.groups()

答案 6 :(得分:0)

另一个答案是使用“分配和测试”方法,允许在O'Reilly Media 2002年7月第1版 Python Cookbook 和{{{}中发布的单个语句中进行分配和测试。 3}}在Activestate。它是面向对象的,其关键在于:

# from http://code.activestate.com/recipes/66061
class DataHolder:
    def __init__(self, value=None):
        self.value = value
    def set(self, value):
        self.value = value
        return value
    def get(self):
        return self.value

可以通过添加下面显示的自定义__call__()方法稍微修改一下,以提供另一种检索实例值的方法 - 虽然不太明确,但对于'DataHolder'来说似乎是完全合乎逻辑的事情。我想是在被叫时要做的事。

    def __call__(self):
        return self.value

允许重写您的示例:

r = DataHolder()
for s in strings:
    if r.set(regex.match(s))
        print r.get().groups()
# or
        print r().groups()

正如原始配方中所提到的,如果你经常使用它,将它和/或它的实例添加到__builtin__模块以使其全局可用是非常诱人的,尽管潜在的缺点:< / p>

import __builtin__
__builtin__.DataHolder = DataHolder
__builtin__.data = DataHolder()

正如我在对这个问题的另一个答案中提到的,必须注意这种方法仅限于一次只保存一个结果/值,因此需要多个实例来处理需要多个值的情况同时保存,例如嵌套函数调用,循环或其他线程。这并不意味着你应该使用它或其他答案,只需要付出更多的努力。