Tutorial :What is the most Pythonic way to provide a fall-back value in an assignment?



Question:

In Perl, it's often nice to be able to assign an object, but specify some fall-back value if the variable being assigned from is 'undef'. For instance:

my $x = undef;  my $y = 2;  my $a = $x || $y;  

After this,

$a == 2  

Is there a concise way to achieve this in Python if the value x is None, or would a full-on ...

if x is not None      a = x  else      a = y  

... be the most Pythonic way to achieve this?

EDIT: Apologies, as has been pointed out by several commenters, I wasn't really talking about the value being undefined, but 'undef' in Perl, which is not really the same thing. But the question as originally worded didn't make this clear.


Solution:1

Since 2.5:

If you want to fall back only on None:

a = x if x is not None else y   

If you want to fall back also on empty string, false, 0 etc.:

a = x if x else y   

or

a = x or y   

As for undefined (as never defined, a.k.a. not bound):

try:    a = x   except NameError:    a = y  

or a bit more hackish (I'd not really recommend that, but it's short):

a = vars().get('x',y)  


Solution:2

first you can do your full-on with a ternary:

a = y if x is None else x  

but it doesn't solve your problem. what you want to do is more closely implemented with:

try:      a = x  except:      a = y  


Solution:3

Just some nitpicking with your Perl example:

my $x = undef;  

This redundant code can be shortened to:

my $x;  

And the following code doesn't do what you say it does:

my $a = $x || $y;  

This actually assigns $y to $a when $x is false. False values include things like undef, zero, and the empty string. To only test for definedness, you could do the following (as of Perl 5.10):

my $a = $x // $y;  


Solution:4

I am quite convinced that there is no 'pythonic' way to do this, because this is not a pattern that is pythonic. Control should not reach an undefined variable reference in elegant code. There are similar ideas that are pythonic. Most obvious:

def myRange(start, stop=None):      start, stop = (0, start) if stop is None else (start, stop)      ...  

What's important is that stop is defined in scope, but the caller didn't have to pass it explicitly, only that it has taken it's default value, altering the semantics of the arguments, which in effect causes the first argument to be optional instead of the second, even where the language does not allow that without this clever trick.

That being said, something like this might follow the premise without using a try-catch block.

a = locals().get('x', y)  


Solution:5

There's python's ternary operation:

a = x if x is not None else y  

Available in 2.5 and up.


Solution:6

I think this would help, since the problem comes down to check whether a variable is defined or not:
Easy way to check that variable is defined in python?


Solution:7

Most of the solutions relying on if statements don't work for the case where x is 0 or negative.

>>> x = 0  >>> y = 2  >>> a = x or y  >>> a  2  >>>   

If you knew the name of the variable ahead of time you could look for like so:

if 'x' in dir():      a = x   except:       a =y  

However that solution seems kind of sloppy to me. I believe the best method is to use a try except block like so:

try:      a = x  else:      a = y  


Solution:8

One way to rewrite...

if x is not None      a = x  else      a = y  

..is:

x = myfunction()    if x is None:      x = y    print x  

Or, using exceptions (possibly more Python'y, depending on the what the code is doing - if it returns None because there was an error, using an exception is probably the correct way):

try:      x = myfunction()  except AnException:      x = "fallback"    print x  

All that said, there really isn't anything wrong with you original code:

if x is not None      a = x  else      a = y  

It's long, but I find that far easier to read (and much more Pythonic) than either of the following one-liners:

a = x if x is not None else y  a = x or y  


Solution:9

If it's an argument to a function you can do this:

def MyFunc( a=2 ):      print "a is %d"%a    >>> MyFunc()  ...a is 2  >>> MyFunc(5)  ...a is 5  

[Edit] For the downvoters.. the if/else bit is unnecessary for the solution - just added to make the results clear. Edited it to remove the if statement if that makes it clearer?


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »