X or y: acceptable idiom or obfuscation?

I need to extract values ​​from a variable, which may be None, with some default values. I wrote this code first:

if self.maxTiles is None: maxX, maxY = 2, 2 else: maxX, maxY = self.maxTiles 

Then I realized that I could shorten it to:

 maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2) 

But then I realized that this might be the most concise and easy to read:

 maxX, maxY = self.maxTiles or (2, 2) 

Is the latter acceptable or too hacky?

+4
source share
6 answers

Oh in particular

 self.maxTiles if self.maxTiles is not None else (2, 2) 

I found that the "double negatives" of the general form if not A: B else: C (whether expressions or expressions) can be quite confusing / misleading; this is not literally if not .. else , but moving not does not cause the "double negative" to disappear.

So, in general, I'm just rewriting such constructs in if A: C else: B In this particular case, if I chose the form of the ternary operator, I would name it as

 (2, 2) if self.maxTiles is None else self.maxTiles 

In a more general question: a = b or c fine if and only if you really want to use c for any false value of b - it is impractical to deal with b as None . IOW, b or c is the best way to express

 b if b else c 

but this is not a way of expressing a similar expression where the main test, and not b is None . Theoretically, if you “know” that the only possible false value for b is None , they are semantically equivalent, but this strong limitation “only possible false value” will not be obvious to readers / developers of your code - and if you need to add a comment so that to explain that any advantages of laconicism that or may require will be nullified ... it is better, when possible, to “say it in code” and not have the code unclear and needing comments to clarify exactly what it does and when (comment the ones that are really useful are more likely to be those that explain, and not what and when [[the code itself should show this! -)]], but rather why , when it is not obvious - that the purpose of the application is served by this particular tidbit of code functionality).

+6
source

Along with gddc's answer (about issues suggesting maxTiles is a tuple), I will probably do the second option, but add brackets for clarity:

 maxX, maxY = (self.maxTiles) if (self.maxTiles is not None) else (2, 2) 
+4
source

If you do this at the start of a function , I would use a longer form, as it is more idiomatic and instantly recognizable. Yes, this is more lines, but you save almost nothing, and short lines that fit into 79 lines of characters = good.

Plus, if you ever have to tweak the logic or add extra steps, you are likely to return to a long form.

+4
source

I avoid the syntax y if x else z when I can. This is inherently ugly, non-intuitive syntax and one of the big mistakes in Python design. This expression is out of order: x evaluates to y. It is not intuitive; it naturally reads as "if x, then y, else z". The C syntax gives us the decades-long established routine for this: x? y:z x? y:z . Python did this very wrong.

However, ternary syntax is the wrong mechanism for providing defaults. In self.maxTiles if self.maxTiles is not None else (2, 2) note the redundancy: you must specify self.maxTiles twice. This is repeated, so more work is required to read the code. I have to read it twice to make sure it does not say, for example, self.minTiles if self.maxTiles is not None else (2, 2) .

self.maxTiles or (0,2) avoids these problems; this is completely clear at a glance.

One warning: if self.maxTiles () either 0 or another false value, the result will be different. This is probably acceptable based on what you seem to be doing, but keep that in mind. This is a problem when providing a default value for a boolean or integer value, and you really need the is None test. For those whom I prefer a simple conditional, but sometimes it disappears from the triple expression.

Change A more understandable way to write a conditional version is:

 if self.maxTiles is None: maxX, maxY = 2, 2 else: maxX, maxY = self.maxTiles 
+3
source

You are encoding a perfectly acceptable idiom. In fact, I find it more readable than the first two.

My only consideration is that you do two things on the same line to provide defaults and unpack them in x, y. This may be more clear if you divide them into two parts.

 maxTiles = self.maxTiles or (2, 2) maxX, maxY = maxTiles 

It also rejects criticism of gddc, although this is not a very serious matter.

+1
source

I don't like using or and and as a replacement for the ternary operator in Python. I ran into problems like a value of 0 , which is being treated as false too many times when I was just planning to check for None . I find it much better to be explicit, even if it is more verbose, so the best second example is:

 maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2) 
0
source

All Articles