Will pythonic use `or`, similar to how PHP will use` or die () `?

Is it possible to use pythonic or , similar to how PHP will use or die() ?

I am using quiet or print(stuff)
instead of if verbose: print(stuff)
recently.

I think it looks better, they do the same, and it saves on line. Would it be better than the other in terms of performance?

The bytecode for both looks pretty much the same to me, but I really don't know what I'm looking for ...

or

 2 0 LOAD_FAST 0 (quiet) 3 JUMP_IF_TRUE_OR_POP 15 6 LOAD_GLOBAL 0 (print) 9 LOAD_CONST 1 ('foo') 12 CALL_FUNCTION 1 (1 positional, 0 keyword pair) >> 15 POP_TOP 16 LOAD_CONST 0 (None) 19 RETURN_VALUE 

vs if

 2 0 LOAD_FAST 0 (verbose) 3 POP_JUMP_IF_FALSE 19 3 6 LOAD_GLOBAL 0 (print) 9 LOAD_CONST 1 ('bar') 12 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 15 POP_TOP 16 JUMP_FORWARD 0 (to 19) >> 19 LOAD_CONST 0 (None) 22 RETURN_VALUE 
+6
source share
2 answers

No, this is definitely not Pythonic. Many of the decisions taken along this path specifically precluded this kind of coding.


The correct way to write this is the obvious way:

 if verbose: print(stuff) 

Or, if computing stuff itself is not expensive / dangerous / irrevocable, just wrap print in a function that checks the flag:

 def printv(*args, **kwargs): if verbose: print(*args, **kwargs) 

... so you can just do it, which is about as concise as you are going:

 printv(stuff) 

Or, even better, use logging instead of reinventing the wheel.


But what if stuff expensive and you really want to keep the string?

Well, you probably don't really need to keep the line, and that always sacrifices readability for short; Reading counts is a key part of Zen of Python . But Python allows you to place a single-line set on the same line as the condition:

 if verbose: print(stuff) 

As PEP 8 puts it, "sometimes it's okay," but it is "usually discouraging." Because Guido put it in an email on the Idea mailing list: “If you have to keep the line, use the single-line if statement, not something smart. But if you have to save the line, I probably don't want to read your code . "

If you want this to be in an expression (which you should not, as I will explain below), or you want to technically follow PEP 8 in a letter when there is a clear violation of this spirit:

 print(stuff) if verbose else None 

So what is not Pythonic about this?

First, you use the print result in an expression, although print does not have a useful result and is only caused by its side effects. This is misleading.

In general, Python has only one side effect per line, and this happens as far as possible, which makes it easy to degrease the code and see what changes. This is reinforced by a strong gap between operators and expressions (and, for example, assignments are statements), methods with side effects, idiomatically returning None instead of self , etc.

But even ignoring all this, using and and or only for short circuits, and not for their results, is potentially confusing and, at least in some people's minds, ugly. That's why the ternary expression ( spam if eggs else beans ) was added: so that people do not write eggs and spam or beans . Why is this confusing? Firstly, it doesn't read at all like English unless you read more Perl code than real English. For another, it is very easy to accidentally use a valid value that turns out to be false; you know you are not doing this, and to be sure of it when you see if , but you do not see it. Also note that print(stuff) if verbose else None makes it explicit that you are creating a value that you then do nothing; Explicit is always better than implicit, but especially when you are doing something unusual.


Finally, regarding performance: (a) who cares, and (b) why not measure it, and not try to guess by reading a bytecode that you don't understand?

 In [511]: quiet = True In [512]: %timeit quiet or None 10000000 loops, best of 3: 48.2 ns per loop In [513]: verbose=False In [514]: %timeit if verbose: pass 10000000 loops, best of 3: 38.5 ns per loop 

So, you, in the case of fast pass, the if is actually about 20% faster and not slower - and they are both so fast that they are unlikely to ever affect your program. If you do this a billion times in a difficult cycle and need to squeeze this performance out, you will want to get the rest out of the cycle, even if it means repeating yourself with two close clones of the same code (especially considering that a cycle without print more likely to fit into cache, etc.).

If you want to know why, well, you should take a look at the implementation of these bytecodes on a specific version of the specific implementation that you care about ... but most likely you need to do an additional POP_TOP instead of the fact that one of them is combined with the previous operation, is part of the difference.

+18
source

I don't think this is pythonic. ("Explicit is better than implicit").

You can write

 if verbose: print(stuff) 

therefore, if you desperately need to keep the reference line down, you can.

The most pythonic way ("Reading counters") will still use

 if verbose: print(stuff) 
+3
source

Source: https://habr.com/ru/post/977513/


All Articles