I have a v2.5 Python code which I cannot control, as it is being exported from a third party software which supports Python v2.5.
I have Python v3.3 on my machine and I want, somehow, to emulate the v2.5 using the C API. My main concern is the integer division which differs between v2.x and v3.x.
For example I have the code below:
a=1
b=a/2
c=a/2.
I want somehow this to be interpreted (using the v3.x) as:
a=1
b=a//2
c=a/2.
Can I do something about that? Is there any way to interpret the code as if I had Python v2.5? I suppose that the 2to3 script does not work for my case, neither the six module.
I also found this question relative to mine: Python 2 and Python 3 dual development
Thanks
This sounds like a bad idea—and you're going to have much more serious problems interpreting Python 2.5 code as Python 3, like every
exceptstatement being a syntax error, and strings being the wrong type (or, if you fix that,s[i]returning an int rather than a bytes), and so on.The obvious thing to do here is to port the code to a Python that's still supported.
If that really is impossible for some reason, the simplest thing to do is probably to write a trivial Python 2.5 wrapper around the code you need to run, which takes its input via
sys.argvand/orsys.stdinand returns results viasys.exitand/orsys.stdout.Then, you just call it like this:
But if you really want to do it, and this is really your only problem… this still isn't the way to do it.
You'd have to go below the level of the C API, into the internal type objects like
struct PyFloat_Type, access theirtp_as_numberstructs, and copy theirnb_floordivfunctions to theirnb_truedivslots. And even that may not change everything.A much better solution is to build an import hook that transforms the AST before compiling it.
Writing an import hook is probably too big a topic to cover in a couple of paragraphs as a preface to an answer, so see this question for that part.
Now, as for what the import hook actually does, what you want to do is replace the
MyLoader.exec_modulemethod. Instead of this:You're going to do this:
So, how do we "manipulate tree in some way"? By building a
NodeTransformer.Every
/expression is aBinOpnode, where theopisDivnode with no attributes, and theleftandrightare the values to divide. If we want to change it into the same expression but with//, that's the sameBinOp, but where theopisFloorDiv.So, we can just visit
Divnodes and turn them intoFloorDivnodes:And our "# manipulate tree in some way" becomes:
If you want to choose between
floordivandtruedivdepending on whether the divisor is an integral literal, as your examples seem to imply, that's not much harder:But I doubt that's what you actually want. In fact, what you actually want is probably pretty hard to define. You probably want something like:
floordivif both arguments, at runtime, are integral valuesfloordivif the argument that will end up in control of the__*div__/__*rdiv__(by exactly reproducing the rules used by the interpreter for that) is an integral value.Anyway, the only way to do this is to replace the
BinOpwith aCallto amydivfunction, that you write and, e.g., stick inbuiltins. That function then does the type-switching and whatever else is needed to implement your rule, and then eitherreturn a/borreturn a//b.