Please rewrite the above code with your directives and see for yourself how much more cluttered and repetitive it looks.
def how_height(obj):
$ version >=3.11
match obj.height:
case h if h < 500:
return "low"
case h if 500 <= h <= 1000:
return "middle"
case h if h > 1000:
return "high"
case _:
return "invalid height"
$ _
if obj.height < 500:
return "low"
elif 500 <= obj.height <= 1000:
return "middle"
elif obj.height > 1000:
return "high"
else:
return "invalid height"
$
Is there anything wrong? Just in different version run different codes.
If the code want to do it best in any version it support, this is not a problem.
That proves my exact point. Your code now has to repeat all the conditions and actions in two places, increasing the readers’ cognitive load with twice the code they really need to read, and when time comes to make a modification to any of the conditions and actions, you’d have to modify two places instead of one, or risk the two versions going out of sync, creating a maintenance nightmare.
The maintenance argument assumes that the same semantics can be expressed once and reused across all supported Python versions. That assumption does not hold here.
Newer Python versions provide language constructs with stronger guarantees that older versions fundamentally cannot express. The duplication is therefore intentional and version-scoped, not accidental.
This is a conscious trade-off: explicit version-specific implementations in exchange for correct and optimal semantics per version. If one prefers uniform code at the cost of weaker guarantees, that is a valid choice — but it is a different goal.
pyv is explicitly designed for the former case, not the latter.
In fact, you can also write it in two modules. One for higher version and one for lower. But it will repeat more and more difficult to maintain.
To be quite honest, this is a terrible demonstration of the match statement. You’re not matching on anything, you’re just using conditions. So this is FAR better expressed simply by doing the if/elif tree, possibly (as has already been mentioned) capturing obj.height into a local if you’re worried about it changing.
This is how things are usually done. A new feature is introduced; you don’t use it until you can drop support for every prior version. You still need to support Python 3.8 on that Raspberry Pi that’s running your app? Stick to the featureset of Python 3.8.
Give us an actual example where the old way doesn’t work on the new version and there’s a syntactic difference so you can’t simply use a regular if sys.version, and then we can discuss. Those are incredibly rare, and usually, each one will have its own solution.
However, the new syntax can usually solve the question better. If a new syntax was proposed just for easier to review, it is difficult to be accepted. For this place, you need to prove that the safety, the performance and many other indicators are same with new syntax or not.
For future, the “pyv” can package the module smaller (it preprocessing the file and the version branches are disappear in final python file) and better (it can support old version and it will use new syntax in higher version for doing it best). The “supporting for old version” and “using new syntax to behave better in new version” can be together by “pyv” way.
FYI, this is the kind of thing I had in mind (it doesn’t cause any real hardship, and there is no great efficiency improvement to be had):
Before:
from ctypes import *
import sys
if sys.platform=='win32':
lib_name = 'project_lib.dll'
load_library = windll.LoadLibrary
else:
lib_name = 'project_lib.so'
load_library = cdll.LoadLibrary
example.pyv
from ctypes import *
import sys
$ platform == "win32"
lib_name = 'project_lib.dll'
load_library = windll.LoadLibrary
$ _
lib_name = 'project_lib.so'
load_library = cdll.LoadLibrary
Is there any efficiency to be had at all? Wouldn’t it have the exact same effect as a simple if statement? There’s no syntactic differences, so ordinary conditionals should be fine here.
You write “no great efficiency improvement”, also the OP writes
As it stands now, pyv is not efficient at all. If one executes a python script, Cpython often caches the generated bytecode in a __pycahce__ directory. The pyv tool does not do that, instead one has the overhead of the pyv tool that tokenizes the input file, generates a new source in memory and hands that to exec. So, the script gets parsed and compiled every time it is executed.
How? How does it solve the question “better”, and what does “better” even mean here?
For future, the “pyv” can package the module smaller (it preprocessing the file and the version branches are disappear in final python file)
How much benefit would you have, compared to the hassle of publishing multiple different branches? I suspect the performance considerations are going to be negligible here. The cost of a one-time conditional check (on module import) is going to be so small compared to any sort of real work being done that it would be difficult to even measure, let alone be worth chasing.
And, again, this is still predicated on wanting:
- To support multiple versions
- Where the old version of Python cannot compile the new code
- And the new version of Python should not run the old code.
That is a LOT to ask for. Do you have a single example of it?
The “pyv” is preprocessing the file and can write to file, so finally in setuping, the “pyv” can make the pyv file to python file. The running this file is often used to test whether the code is wrong.
How much benefit would you have, compared to the hassle of publishing multiple different branches?
It is not what I can answer, but what the specific module can answer.
This case appears when the module someplace want new syntax’s advantage in runtime (maybe the module author find it) but need to support for the python version that not support the new syntax.
Anyway, you didn’t response the idea that “the final wheel can be smaller”.
Anyway, you didn’t response the idea that “the final wheel can be smaller”.
That would only be the case if you publish multple wheels for different versions, which means more deployment hassles and upgrade issues. And you didn’t respond to the complete lack of actual use-cases. You could have an identical sized wheel just by using the older style and not having two versions.
In fact, I am search the use-cases. However, my computer has memory crisis so it is processing slowly.
The “pyv” is preprocessing the file and can write to file
It could. But this is not what pyv actually does if called from the command line.
Is there any efficiency to be had at all?
No! Not in terms of time at least. Perhaps in terms of space though, it could allows a larger number of smaller wheels to be built.
Yes. As I said earlier, I’m interested in the pre-processor. For this project to have legs, OP should delete the exec calling launcher, instead of forcing his users to force that on their users.