pythonif-statementvariable-assignment

How to assign a variable in an IF condition, and then return it?


def isBig(x):
   if x > 4: 
       return 'apple'
   else: 
       return 'orange'

This works:

if isBig(y): return isBig(y)

This does NOT work:

if fruit = isBig(y): return fruit

Why doesn't the 2nd one work!? I want a 1-liner. Except, the 1st one will call the function TWICE.

How to make it 1 liner, without calling the function twice?


Solution

  • I see somebody else has already pointed to my old "assign and set" Cookbook recipe, which boils down in its simplest version to:

    class Holder(object):
       def set(self, value):
         self.value = value
         return value
       def get(self):
         return self.value
    
    h = Holder()
    
    ...
    
    if h.set(isBig(y)): return h.get()
    

    However, this was intended mostly to ease transliteration between Python and languages where assignment is directly supported in if or while. If you have "hundreds" of such check-and-return in a cascade, it's much better to do something completely different:

    hundreds = isBig, isSmall, isJuicy, isBlah, ...
    
    for predicate in hundreds:
      result = predicate(y)
      if result: return result
    

    or even something like

    return next(x for x in (f(y) for f in hundreds) if x)
    

    if it's OK to get a StopIteration exception if no predicate is satisfied, or

    return next((x for x in (f(y) for f in hundreds) if x)), None)
    

    if None is the proper return value when no predicate is satisfied, etc.

    Almost invariably, using (or even wishing for;-) the Holder trick/non-idiom is a "design smell" which suggests looking for a different and more Pythonic approach -- the one case where Holder is justified is exactly the special case for which I designed it, i.e., the case where you want to keep close correspondence between the Python code and some non-Python (you're transliterating a reference algorithm in Python and want it working first before refactoring it into a more Pythonic form, or you're writing Python as a prototype that will be transliterated into C++, C#, Java, etc, once it's working effectively).