@bentraje The Python tag must be evaluated in every redraw of the scene (not just on every frame but far more often; try this by insert a Print in the code...) because it may not just depend on variables but on values from the scene (e.g. "if the object X is placed farther away than 1000 units then move object Y to..."). Keeping track of original values and comparing them with current values like this is nigh impossible (requiring analysis of code semantics), so the tag will be simply re-evaluated whenever encountered.
You can insert an "early exit" in the tag, of course, by testing for changed variables yourself (as you as programmer have more information on the semantics than the Python interpreter/compiler). But you will need to store the values to compare with somewhere, and you will need to take into account that the execution may not happen in frame sequence (e.g. when the user scrubs the timeline backwards).
As for the original question, I tend to put calculations into Python nodes inside the XPresso because plain math calc creates TONS of XPresso nodes that tend to become very confusing. On the other side I keep XPresso nodes whenever I want to see the affected objects in the circuit directly, or when I need a GUI for adapting something (e.g. Range Mapper with spline interface), or when the node does complicated things that I don't want to reprogram in Python (Hair intersection? ... nah, never used that ). When the whole thing is easier to maintain as a Python tag in the end, I put it into the tag...
So it's not so much a question of whether the execution is faster, it's pure convenience of the result for me.