2

I'd like to do something like:

def get_foo(): return self._foo or self._foo = Bar() 

I am looking for the cleanest way to do it. Is it possible with or equals?

My attempts failed:

>>> foo = None >>> foo or 'bar' 'bar' >>> foo >>> foo or foo = 'bar' File "<stdin>", line 1 SyntaxError: can't assign to operator >>> foo or (foo = 'bar') File "<stdin>", line 1 foo or (foo = 'bar') ^ SyntaxError: invalid syntax 

3 Answers 3

6

In Python, you cannot use assignments in expressions. So you have to do the assignment and the return statement on two different lines:

def get_foo(self): self._foo = self._foo or Bar() return self._foo 

But in general, it's better to write it out:

def get_foo(self): if not self._foo: self._foo = Bar() return self._foo 
Sign up to request clarification or add additional context in comments.

5 Comments

What's faster? In the first case, is python smart enough to do not the assignment operation if value is set?
Yes. There's basically nothing in it.
@WooYek: If you worry about performance that much, then either this method should be eliminated altogether and go for static initialized members, or Python may not be the language you're looking for. In general, writing it the way you want it to (the short way) is bad because it's unreadable and leads to unmaintainable code.
I'm just curious about performance and python's cleverness. I do not agree that using syntactic sugar leads to unreadable and unmaintainable code, if there is a way to make the code cleaner it should be used. Reading ||= in ruby always get's me little bit confused for a moment, but I'm no ruby programmer and I expect that ruby programmers read it just fine.
In the first case, Python will always do the assignment.
4

Python's assignment operator doesn't pass through the assigned value, primarily because in other languages it has proven to be a fruitful generator of accidental =/== bugs. Instead you have to be explicit:

def get_foo(self): if self._foo is None: self._foo= Bar() return self._foo 

You can make an expression with side-effects if you really want to:

def set_foo(self, v): self._foo= v return v return self._foo or self.set_foo(Bar()) 

but it's generally considered a Bad Thing.

Comments

-2

I might be wrong, but this looks like a job for the ||= operator.

def get_foo(): return self._foo |= Bar() 

My Perl is rusty at best, but ||= seems to return an R-value, so the return should work.

Edit: Woopsie, this is Python. It doesn't have a ||=. Bummer.

Then I'd use the simulated ternary operator:

def get_foo() self._foo = self._foo is None and Bar() or self._foo return self._foo 

Edit 2: Python has a real ternary operator. Use it instead of the above.

def get_foo() self._foo = Bar() if self._foo is None else self._foo return self._foo 

9 Comments

There is a ternary operator in Python (2.6+ I believe): self._foo = self._foo if self._foo else Bar().
"cond and cond-is-true-value or cond-is-false-value" has always been error prone (if the cond-is-true-value is one of the Python values like 0, [], {}, etc. that Python considers to be False in its booleanness). Initialize self._foo to None, and use this proper ternary (beginning in Py2.5): self._foo = Bar() if self._foo is None else self._foo. But why assign self._foo to self._foo in the 99% case where self._foo is no longer None once it has been initialized? Just use if self._foo is None: self._foo = Bar() followed by return self._foo. No ternary magic, just easy-to-read code.
@egarcia: "only if 'cond' doesn't return a boolean"?? Every Python value has an implicit boolean evaluation. The bugs occur in cases like x = x is None and 0 or x - surprise, you never get the 0 assignment because bool(0) is False. Far and away the most common use of this idiom is for lazy initialization of an expensive-to-evaluate attribute (such as a database field), where the attribute is initialized to None, and then on first access, it gets set to its real value. For the following 'n' accesses (might be 0, might be a million), the lazy-init value or an updated non-None value is used.
@egarcia: (ran out of room) - so to summarize 'cond and x or y' is bug-prone when bool(x) is False, in which case, you will get y, regardless of whether cond is True or False.
@Paul McGuire: I understand what you mean about bugginess now. You are right. I've also fixed the None and is thingie.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.