0

Consider the following program, which is saved in a file named script.py:

x = 2/3
x

(This is a script in Python, but actually my real script is in R -- I am using this Python script just for illustration of what I am wanting.)

Now, I want to use a second program in Python to get the numerical value of variable x calculated in script.py.

The following program accomplishes that but only partially, in the sense that the number with all decimal digits is not returned. In truth, float(s) does not have the same decimal precision as x.

import subprocess

cmd_line = ["python", "script.py"]
s = subprocess.check_output(cmd_line, text=True)
float(s) 

What I want to obtain is the value of x with the same precision as it gets in script.py.

EDIT

This question was closed because -- it is argued -- it is a duplicate of previous question. I am not looking for a way to get arbitrary decimal precision: I am looking for a way to pass a numerical result of a Python script to a second Python script.

Please, I kindly and respectfully ask you for reopening the question.

PaulS
  • 21,159
  • 2
  • 9
  • 26
  • 1
    That example doesn't send anything to stdout so `float(s)` doesn't work. You'd want to format a string for stdout and that's where you'd make your precision decision. – tdelaney Oct 17 '22 at 22:28
  • Thanks, @tdelaney, for your comment. In reality, I do get a result with the code above: `0.6666666666666666`. – PaulS Oct 17 '22 at 22:30
  • 1
    `print(f"{x:.16f}")` should do – tdelaney Oct 17 '22 at 22:32
  • Thanks, but my question persists: How to pass a *numerical* variable from a script to another one? I am not sure whether it is possible. – PaulS Oct 17 '22 at 22:40
  • It seems that the person that closed this question **misread** it and **confused** with something I did not ask in my question! – PaulS Oct 17 '22 at 22:44
  • 1
    Agreed. That's not what was being asked here. As for passing a numerical value... if they are separate programs, they have to serialize the value somehow. Its common to convert things to strings as that has the fewest common dependencies - anything that can parse strings, works. You could do some sort of byte serialization (the ctypes package for instance), but that is more difficult. You could have shared memory or named pipes or a queue. These are all more difficult and have more common dependencies. – tdelaney Oct 17 '22 at 22:53
  • @tdelaney: probably, I was not clear enough while asking my question -- I am sorry about that. But I have added an edit, where I clarify the point. My question -- I guess -- is very far from trivial! And I am not sure there is a solution! – PaulS Oct 17 '22 at 22:57
  • 1
    Hi, yes, you weren't clear enough in the original question with what you really desired initially, you should have included precisely what value you want to pass, and what value you expect to receive and where exactly the mismatch is (more specifically, a detailed example), I've seen too many questions that looks like wanting arbitrary floating point precision and the way it was worded originally seemed to ask for that. – metatoaster Oct 18 '22 at 01:56
  • Thanks, @metatoaster, for your comment! I will try to follow your directions in future questions. – PaulS Oct 18 '22 at 09:05
  • 1
    "I am looking for a way to pass a numerical result of a Python script to a second Python script." - but I thought your "real script is in R"? Using the same language on both ends opens up different options, such as making use of `import` and then passing arguments to functions. That said, only *raw bytes* can be passed between processes - it is up to both ends of that communication to establish the *protocol* for interpreting the data. **Just like** when you read and write a file; it only stores raw bytes. (Yes, "ASCII text" is a protocol.) – Karl Knechtel Oct 18 '22 at 17:43
  • Thanks, @KarlKnechtel, for your comment. Yes, initially I imagined that to pass parameters between two Python scripts would be similar to pass parameters between a R script and a Python script -- that is why I wrote "I am looking for a way to pass a numerical result of a Python script to a second Python script.". – PaulS Oct 18 '22 at 18:59

2 Answers2

1

The most common way to pass a numerical value to another script is to serialize it. There are many options ranging from JSON to python's own internal pickle protocol. Since this is a single value, you could even just print the python string representation.

x = 2/3
print(f"{x:.16f}")

Your reader would not have to change.

A note about "the same decimal precision as x", its likely 34 digits and you could get that with a different format of the string

print(f"{x:.33e}")

I'm not sure how that's done in R.

tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • 1
    You would use `repr` or `float.hex` for this purpose, or `{x:.17g}` if you had to use a `printf`-like format. 33 digits is way too many. – Davis Herring Oct 17 '22 at 23:18
  • 1
    @DavisHerring - You could use `repr` but why not something that lets you print better precision? And lets not forget, the real code will be R, so a string formatting operation is reasonable. And why not use maximum precision? Its a computer it doesn't get mad if the string is too long. – tdelaney Oct 17 '22 at 23:26
  • From our discussion, it occurred an idea to me: R can run Python through [reticulate](https://rstudio.github.io/reticulate/). Hence, maybe one can use `pickle` as described at: [How do you share a variable between two Python scripts?](https://www.quora.com/How-do-you-share-a-variable-between-two-Python-scripts). – PaulS Oct 17 '22 at 23:33
  • @tdelaney: Printing additional digits is not actually adding information, since it still parses as the same `float` value. It is a feature that `repr` provides exactly as many digits as needed to guarantee that. Part of the reason that I gave the correct (fixed) number of digits for `%g` is for portability to other environments. All floating-point values (as dyadic rationals) terminate in decimal, but the “maximum precision” is about 1100 digits, which is hardly useful. – Davis Herring Oct 18 '22 at 00:14
  • @tdelaney: Your comments have set my research in the right direction, and I have now, in consequence, found out that R has also a serialization format, which can easily be read in Python! Thank you so much for your help and patience! – PaulS Oct 18 '22 at 09:11
0

Thanks to the discussion we had (me, @tdelaney, @DavisHerring, to whom I very much thank), I have found out a solution, which I describe below. R can run Python code through reticulate, and therefore one can write the numerical variables in a pickle file to send them to the Python script.

This solution does not need subprocess.

R script:

library(reticulate)

py$x <- 2/3

py_run_string(
'import pickle 
with open("/tmp/myfile.pickle", "wb") as outfile: 
    pickle.dump(x, outfile)

outfile.close()')

This will write x in a pickle file.

Python code that reads the pickle file:

import pickle

with open("/tmp/myfile.pickle", "rb") as infile: 
    x = pickle.load(infile) 
   
infile.close()
print(x)

This solution was also inspired in this code:

How do you share a variable between two Python scripts?


A simpler approach consists in saving the objects one wants to pass to the Python script as a RDS file (a R data serialization format). Subsequently, the objects saved in the RDS file can be read by using Python package pyreadr.

R script:

x <- 2/3
saveRDS(x, file = "/tmp/file.rds")

Python code that reads the RDS file:

import pyreadr

result = pyreadr.read_r('/tmp/file.rds')
result[None].iloc[0,0]
PaulS
  • 21,159
  • 2
  • 9
  • 26