[Carlos Alberto Reis Ribeiro, staring at the disassembled Python bytecodes for ( 16 * ( 15j + ( 4.2 - 3.9 ) + 20 ) / -2 ) % 5] > ... > 4) Now the ugly part. At [25], we load a constant (with the value 2), > and then do a unary minus operation. The question is, does it really > need to be so? No, not really. > There is any good reason not to optimize this, making the conversion > to the negative value in the compiler? The Python compiler does no classic optimizations of any kind at all: expressions are evaluated strictly left-to-right, parentheses are always honored, your code is never moved, shared, rearranged, rewritten or collapsed. WYSIWYG. Most of the time <wink>. Because it does no optimizations, there's no supporting machinery for *doing* optimizations either, so "the first one" it tries is going to be more of a pain than you imagine. In particular, negative integer literals don't exist in Python's grammar (only non-negative integer literals exist), and Python compiles straight from parse tree to bytecode. So even that trivial little optimization would require a (non-existent) peephole optimizer doing pattern matching on the parse tree or bytecode stream. Not worth the effort to anyone so far. To the contrary, the utter lack of optimization has saved people countless hours in not needing to track down optimization bugs <0.3 wink>. > 5) Other strange thing: at least in this example, the compiler did > not made any optimization on constant expressions. Right, and it never does. This isn't C, and Python assignments aren't macros, so doing stuff like TOTAL_BYTES = BYTES_PER_SECTOR * SECTORS_PER_TRACK * NUM_TRACKS at module level is a one-time module import cost, no matter how often TOTAL_BYTES is dynamically referenced later. But, yes, doing that inside a loop is a Possibly Poor Idea. > ... > 1) Avoid any unnecessary calculation, specially inside tight loops. I'd amend that to "but only inside tight loops". For typical code, it really doesn't matter elsewhere. > I tend to use lots of explicit calculations, in order to make code > easier to understand. Things like adding/subtracting one, or > calculating an offset for a struct, for instance) are common > applications of this idiom, for example: > > >>> p = a[(3*4+2)-1] # get the second byte of the third DWORD I'll take your word for it that you find that easy to understand <wink>. But note that since Python doesn't have pointers, Python code is blissfully free of fiddly pointer and offset calculations, unless you're faking high-level data structures by hand (in which case you're not really programming in Python anyway ...). > 2) If your expression involves value of mixed types, check > *carefully* the sequence of the calculation. That's crucial advice in any language. > It is possible to optimize the evaluation a little bit by moving > the more complex (and slower) types to the end of the evaluation. More important is that the order of coercions yield a *correct* result. When you first inject a float or complex into a calculation can have profound effects on the numerical result, not just on the speed. Optimizing for speed is darned tricky too. For example, floating multiplies may be *much* faster than int multiplies in Python, because Python checks the latter for overflow but gets no help on that from C: Python's code for multiplying two (small, not unbounded) ints slobbers over 100 lines of C! don't-worry-about-speed-until-you-have-to-ly y'rs - tim
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4