Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python equivalent of Perl/Ruby ||= [duplicate]

Tags:

python

ruby

perl

Possible Duplicate:
Python conditional assignment operator

Apologies for such a simple question, but googling ||= isn't very helpful ;)

Is there an equivalent in Python to the ||= statement that's present in Ruby and Perl?

For example:

foo = "hey"
foo ||= "what"    # assign foo if it's undefined
# foo is still "hey"

bar ||= "yeah"
# bar is "yeah"

Also what's the general term for something like this? Conditional assignment was my first guess but the Wikipedia page isn't quite what I had in mind.

like image 707
benui Avatar asked Jan 30 '12 05:01

benui


3 Answers

A tad bit more verbose, but the easiest is

foo = "hey"
foo = foo or "what"
#foo is still "hey"

bar = None
bar = bar or "yeah"
#bar is "yeah"

You can also use the ternary operator

bar = None
bar = bar if bar else "yeah"

However, if I understand you, ||= assigns variables that weren't previously defined, without complaint? I had no idea.

To do that in the local scope, this ugly duckling could work

bar = locals()['bar'] if 'bar' in locals() else 'yeah'

EDIT:

Just saw the duplicate, and it has plenty of solutions as well :) For those too lazy to look, they also include a nicer variant on my last one

foo = foo if 'foo' in locals() else 'hey'

but this won't work for undefined variables, only falsy values will be replaced and undefined will raise a NameError. This next one will, OTOH, ONLY work for undefined and always keep the same preexisting falsy value, which as @Borodin says is like //= in Perl

foo = locals().get('foo','hey')

and, of course, someone used an exception :(

try:
   v
except NameError:
   v = 'bla bla'
like image 167
Matt Luongo Avatar answered Sep 29 '22 15:09

Matt Luongo


You'll hardly ever have undefined variables in Python, and when you do it usually means you have made a mistake. However, conveniently, most of the sorts of values that are commonly used as defaults (empty containers, zero-length strings, zero, and None) are "falsy" in Python, so you will sometimes see stuff like this that takes advantage of how Boolean operators work in Python:

name = name or "Guido"   # if name is empty, set it to "Guido"
numb = numb or 42        # if numb is zero, set it to 42

The reason this works is that Python stops evaluating or if the first argument is "truthy," which is called short-circuiting, and in either case returns the actual argument, rather than merely True or False, as its result. So if name is "Jim" then "Jim" or "Guido" evaluates to "Jim" because "Jim" is a non-zero-length string and therefore "truthy."

Of course, this doesn't work so well when you don't know the type of the value you're dealing with and/or a "falsy" value is a valid value. However, it works pretty well with things like configuration files and raw_input() where a missing value will return an empty string:

name = raw_input("What is your name? ") or "Guido"

Another common idiom is used when dealing with items in a dictionary. The dictionary class's get() method lets you specify a default value to be used if the variable isn't in the dictionary.

name = values.get("name", "Guido")

This can be used when your function has been passed keyword arguments using the **kwargs convention. You could also use it with variables, as the globals() and locals() functions return, respectively, all global or local variables currently in scope as a dictionary:

name = locals().get("name", "Guido")

However, as I said, you will rarely ever have actually undefined variables in Python. In cases like Web frameworks, you'll be passed query string arguments as a dictionary, for example, and can use the dictionary's .get() method on it.

In the rare case where a name actually does not exist (for example, your configuration file is in Python syntax and you're importing it as a Python module rather than parsing it, and you want users to be able to omit some values... or something equally wacky) then you can use getattr(), which (like dictionary's .get()) accepts a default value:

import config
name = getattr(config, "name", "Guido")    # rather than just name.config

Or just let it throw a NameError and catch it.

like image 35
kindall Avatar answered Sep 29 '22 16:09

kindall


Not sure about the name. The best I could come up with is:

>>> a = 'foo'
>>> a = 'a' in locals() and a or 'what'
>>> a
'foo'
>>> b = 'b' in locals() and b or 'yeah'
>>> b
'yeah'
like image 45
GuillaumeDufay Avatar answered Sep 29 '22 15:09

GuillaumeDufay