开发者

x or y: acceptable idiom, or obfuscation?

I have to extract values from a variable that may be None, with some defaults in mind. I first wrote this code:

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

Then I realized I could shorten it to:

maxX, maxY = self.ma开发者_如何学运维xTiles if self.maxTiles is not None else (2, 2)

But then I realized this might be the most succinct and easily readable:

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

Is the latter acceptable, or too hackish?


About, specifically,

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

I've found that "double negatives" of the general form if not A: B else: C (whether as statements or expressions) can be quite confusing / misleading; this isn't literally an if not .. else, but moving the not doesn't make the "double negative" go away.

So, in general, I just rewrite such constructs to if A: C else: B. In this particular case, if I did choose the ternary-operator form, I'd code it as

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

On to the more general question: a = b or c is fine if and only if you really want to use c for any false value of b -- it's not fine to deal specifically with b being None. IOW, b or c is a better way to express

b if b else c

but it's not a way to express a similar expression where the core test is, instead, b is None. In theory, if you "know" that the only possible false value for b is None, they're semantically equivalent, but that strong "only possible false value" constraint will not be apparent to readers / maintainers of your code -- and if you have to add a comment to explain that, any conciseness advantages that or might claim are nullified... better, when feasible, to "say it in code", rather than have the code be obscure and need comments to clarify exactly what it's doing and when (comments that are really useful are rather those which explain, not the what and the when [[the code itself should show that!-)]], but rather the why when it's not obvious -- what's the application purpose being served by this specific tidbit of code functionality).


Along with the answer of gddc ( of the problems of assuming maxTiles is a tuple), I would probably do the second option, but add parenthesis for clarity:

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


If you're doing this at the beginning of a function, I'd use the longer form as it's more idiomatic and instantly recognizable. Yeah, it's more lines, but you barely save any characters, and short lines that fit into 79 character lines = good.

Plus if you ever have to adjust the logic or add more steps you'd likely revert to the long form anyways.


I avoid the y if x else z syntax when I can. It's inherently an ugly, unintuitive syntax, and one of the bigger mistakes in Python's design. It's an out-of-order expression: x is evaluated before y. It's unintuitive; it's naturally read as "if x then y, else z". C's syntax gives us a decades-established, universally-understood order for this: x? y:z. Python got this one very wrong.

That said, ternary syntax is the wrong mechanism for supplying a default anyway. In self.maxTiles if self.maxTiles is not None else (2, 2), note the redundancy: you have to specify self.maxTiles twice. That's repetitive, so it takes more work to read the code. I have to read it twice to be sure it doesn't say, for example, self.minTiles if self.maxTiles is not None else (2, 2).

self.maxTiles or (0,2) avoids these problems; it's perfectly clear at a glance.

One caveat: if self.maxTiles is () or 0 or some other false value, the result is different. This is probably acceptable based on what you seem to be doing, but keep this in mind. It's an issue when providing a default for a boolean or an integer, and you really do need the is None test. For those I prefer a simple conditional, but will sometimes fall back on a ternary expression.

Edit; a clearer way of writing the conditional version is:

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


You code is perfectly acceptable idiom. In fact I find it more readable than the first two.

My only consideration is you are doing two things in one line, to supply a default and to unpack them into x,y. It maybe more clear if you separate them into two.

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

This also deflect the criticism of g.d.d.c, although it is not really a serious one.


I don't like using or and and as replacements for a ternary operator in Python. I've run into problems like a 0 value being treated as "false" too many times, when I only intended to check for None. I consider it much better to be explicit, even if its more verbose, so your second example is best:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜