pythonic way to rewrite an assignment in an if statement

前端 未结 7 780
隐瞒了意图╮
隐瞒了意图╮ 2020-12-19 10:37

Is there a pythonic preferred way to do this that I would do in C++:


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

I r

相关标签:
7条回答
  • 2020-12-19 11:06

    Yet another answer is to use the "Assign and test" recipe for allowing assigning and testing in a single statement published in O'Reilly Media's July 2002 1st edition of the Python Cookbook and also online at Activestate. It's object-oriented, the crux of which is this:

    # 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
    

    This can optionally be modified slightly by adding the custom __call__() method shown below to provide an alternative way to retrieve instances' values -- which, while less explicit, seems like a completely logical thing for a 'DataHolder' object to do when called, I think.

        def __call__(self):
            return self.value
    

    Allowing your example to be re-written:

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

    As also noted in the original recipe, if you use it a lot, adding the class and/or an instance of it to the __builtin__ module to make it globally available is very tempting despite the potential downsides:

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

    As I mentioned in my other answer to this question, it must be noted that this approach is limited to holding only one result/value at a time, so more than one instance is required to handle situations where multiple values need to be saved simultaneously, such as in nested function calls, loops or other threads. That doesn't mean you should use it or the other answer, just that more effort will be required.

    0 讨论(0)
  • 2020-12-19 11:07

    There is no pythonic way to do something that is not pythonic. It's that way for a reason, because 1, allowing statements in the conditional part of an if statement would make the grammar pretty ugly, for instance, if you allowed assignment statements in if conditions, why not also allow if statements? how would you actually write that? C like languages don't have this problem, because they don't have assignment statements. They make do with just assignment expressions and expression statements.

    the second reason is because of the way

    if foo = bar:
        pass
    

    looks very similar to

    if foo == bar:
        pass
    

    even if you are clever enough to type the correct one, and even if most of the members on your team are sharp enough to notice it, are you sure that the one you are looking at now is exactly what is supposed to be there? it's not unreasonable for a new dev to see this and just fix it (one way or the other) and now its definitely wrong.

    0 讨论(0)
  • 2020-12-19 11:08

    Perhaps it's a bit hacky, but using a function object's attributes to store the last result allows you to do something along these lines:

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

    Or more generically:

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

    Note that although the "value" saved can be a collection of a number of things, this approach is limited to holding only one such at a time, so more than one function may be required to handle situations where multiple values need to be saved simultaneously, such as in nested function calls, loops or other threads. So, in accordance with the DRY principle, rather than writing each one, a factory function can help:

    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()
              ...
    
    0 讨论(0)
  • 2020-12-19 11:21

    There's a recipe to make an assignment expression but it's very hacky. Your first option doesn't compile so your second option is the way to go.

    ## {{{ 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/ }}}
    

    As you can see, production code shouldn't touch this hack with a ten foot, double bagged stick.

    0 讨论(0)
  • 2020-12-19 11:22

    How about

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

    or a bit more functional

    for r in filter(None, map(regex.match, str)):
        print r.groups()
    
    0 讨论(0)
  • 2020-12-19 11:31

    This might be an overly simplistic answer, but would you consider this:

    for s in str:
        if regex.match(s):
            print regex.match(s).groups()
    
    0 讨论(0)
提交回复
热议问题