1 Востаннє редагувалося serge (30.12.2016 22:32:17)

Тема: Передати значення змінних у зовнішню програму

Добрий день!
Необхідно передати значення змінних, що визначені в скрипті Пітону, в програму "a.exe" яка написана на C. Текст джерела "a.exe" такий:

#include <stdio.h>
int main(){
  double x1, x2;
  scanf("%lf  %lf", &x1, &x2);
  printf(" %lf + %lf = %lf ", x1, x2, x1 + x2);
  return 0;
}

Наразі єдине, що вдається зробити – це передавати числа, що введені з клавіатури, але не змінні. Так працює наступний код (хоча вивід виходить досить дивний):

import subprocess
p = subprocess.Popen("a.exe", stdout = subprocess.PIPE)
print ( p.stdout.read() )

Але як передати змінні xx1,xx2? Починатися потрібний мені скрипт повинен, здається, так:

import subprocess
xx1 = 1.; xx2 = 2.
p = subprocess.Popen("a.exe", ############)
############

але зробити щось таке, що працює, поки не вдається. Тому прошу про допомогу. Думаю, що проблема розв’язується тривіально, просто я не настільки досвідчений в Python

2

Re: Передати значення змінних у зовнішню програму

Що саме нам треба зробити — пітонівський скрипт просто генерує якісь значення, які потім обробляються сішною програмою? Якщо це все, що ці програми роблять, то в пітонівському скрипті можна просто вивести ці значення на друк, а в командному рядку з'єднати дві програми через пайп:

python SCRIPTNAME.py|a.exe

Це працює в найпростішому випадку — якщо скрипт більш нічого не виводить і ніяк не обробляє вивід зовнішньої програми, яка викликається лише один раз.

3

Re: Передати значення змінних у зовнішню програму

serge написав:

Наразі єдине, що вдається зробити – це передавати числа, що введені з клавіатури, але не змінні. Так працює наступний код (хоча вивід виходить досить дивний):

import subprocess
p = subprocess.Popen("a.exe", stdout = subprocess.PIPE)
print ( p.stdout.read() )

Здається, тут скрипт здійснює перехоплення виводу зовнішньої програми, а ввід лишається стандартним. Вам же треба перехопити ввід і відправити туди свої дані.

4

Re: Передати значення змінних у зовнішню програму

щодо другої відповіді:

Здається, тут скрипт здійснює перехоплення виводу зовнішньої програми, а ввід лишається стандартним. Вам же треба перехопити ввід і відправити туди свої дані.

бачу, цей варіант насправді зовсім не те, що потрібно.

Дякую за пропозицію у першій відповіді. Насправді,

пітонівський скрипт просто генерує якісь значення, які потім обробляються сішною програмою

і

скрипт більш нічого не виводить і ніяк не обробляє вивід зовнішньої програми

Але цей скрипт потрібний мені саме для того, щоб викликати програму багато разів у циклі, кожний раз із новими параметрами. Зараз маю варіант, що працює, але це через створення скриптом файлу „*.ini” перед кожним викликом, котрий у свою чергу зчитується зовнішньою програмою. Це не дуже зручно, тому і шукаю більш просте рішення.

На іншому форумі запропонували щось схоже на такий варіант:

import subprocess
p = subprocess.Popen(["a.exe", "4.", "3."], stdin=subprocess.PIPE)

де "4.", "3." і були б параметами для передавання у зовнішню програму. Запускається така композиція без сповіщень про помилки, але програма працює нібито ніякі параметри не було передано. Тому поки що не знаю розв’язання проблеми. Але, здається, воно дуже близько

5

Re: Передати значення змінних у зовнішню програму

На іншому форумі запропонували щось схоже на такий варіант:

import subprocess
p = subprocess.Popen(["a.exe", "4.", "3."], stdin=subprocess.PIPE)

Очевидно, для цього варіанту треба переписати й сішну програму, щоб вона отримувала дані не через scanf, а через параметри main. Правда, тоді незрозуміло, навіщо перевизначати stdin.

6 Востаннє редагувалося P.Y. (31.12.2016 03:53:42)

Re: Передати значення змінних у зовнішню програму

Так має працювати:

import subprocess
p=subprocess.Popen('a.exe', stdin=subprocess.PIPE)
p.stdin.write(b"1. 2.\n")
p.stdin.close()

Рядок байтів, що передається зовнішній програмі в stdin, можна генерувати програмно:

...
xx1 = 1.; xx2 = 2.
s= ("%s %s\n"%(xx1,xx2)).encode() #python3; в python2 — те ж саме, але без .encode()
p.stdin.write(s)
...
Подякували: koala, serge2

7

Re: Передати значення змінних у зовнішню програму

Клас! Це саме те, чого хотілося добитися! Пізніше викладу кінцеву реалізацію.
З Новим Роком!

8

Re: Передати значення змінних у зовнішню програму

@serge

Приєднуюся до варіанту P.Y щодо субпроцесу. Єдине - підхід може бути простішим:

import shlex
import subprocess
p=subprocess.Popen(shlex.split("a.exe %f %f" % (arg1, arg2), stdin=subprocess.PIPE)
// in the C app, use argv

int main(int argc, char* argv[])
{
    // read argv[1], argv[2] into xxx1, xxx2 with conversion

return 0;
}

9 Востаннє редагувалося serge (02.01.2017 18:40:53)

Re: Передати значення змінних у зовнішню програму

Дуже дякую усім, хто допоміг розібратися в цьому питанні, або звернув увагу. Завдяки цій темі вдалося трохи розкласти по полицям те, що чув про стандартний ввід-вивід і про аргументи main в C.

Перший варіант:

import subprocess
p=subprocess.Popen('a.exe', stdin=subprocess.PIPE)
xx1 = 1.; xx2 = 2.
p.stdin.write( ("%s %s\n"%(xx1,xx2) ).encode() ) #python3; в python2 — без .encode()
p.stdin.close()
#include <stdio.h>
int main()
{
   double x1,x2;
   scanf("%lf", &x1); scanf("%lf", &x2);
   printf( "\n %.1lf + %.1lf = %.1lf\n", x1, x2, x1+x2 );
   return 0;
}

Цей варіант виходить насправді трохи більш громіздким, ніж другий, але він цікавий хоча б тому, що підходить для зв’язки з зовнішньою програмою, яка не обов’язково написана на С або на мові, де використовується щось аналогічне аргументам main. 

Щодо другого варіанту, найпростішою видається така комбінація:

import subprocess
xx1 = 1.; xx2 = 2.
p = subprocess.Popen( "a.exe %f %f" % ( xx1, xx2 ) )
#include <stdio.h>
int main(int argc, char *argv[])
{
   double x1,x2;
   sscanf(argv[1],"%lf",&x1);
   sscanf(argv[2],"%lf",&x2);
   printf( "\n%.1lf + %.1lf = %.1lf\n", x1, x2, x1+x2 );
   return 0;
}

Вона працює, як і варіант зі shlex, запропонований Bartash. Дайте знати, якщо тут щось не є достатньо коректно.
Усім найкращих успіхів!

10

Re: Передати значення змінних у зовнішню програму

serge написав:

Цей варіант виходить насправді трохи більш громіздким, ніж другий, але він цікавий хоча б тому, що підходить для зв’язки з зовнішньою програмою, яка не обов’язково написана на С або на мові, де використовується щось аналогічне аргументам main.

Якщо зовнішній програмі треба передавати певні аргументи - не грає ролі, на якій мові вона написана: підхід один. І цей підхід є більш православним, ніж запис до stdin, імго.

11

Re: Передати значення змінних у зовнішню програму

Bartash написав:
serge написав:

Цей варіант виходить насправді трохи більш громіздким, ніж другий, але він цікавий хоча б тому, що підходить для зв’язки з зовнішньою програмою, яка не обов’язково написана на С або на мові, де використовується щось аналогічне аргументам main.

Якщо зовнішній програмі треба передавати певні аргументи - не грає ролі, на якій мові вона написана: підхід один. І цей підхід є більш православним, ніж запис до stdin, імго.

Це якщо програма маленька й використовується один раз. А якщо для її запуску й ініціалізації тратиться багато часу, а даних треба обробити багато, то має сенс зробити в ній цикл з повторами вводу даних/виводу результату, а в скрипті не запускати її повторно, а передавати дані одному й тому ж підпроцесу. Крім того, командний рядок може мати обмеження довжини, а кількість даних, прочитаних зі stdin, необмежена — якщо нам треба не додати два числа, а, наприклад, перекодувати якісь невідомо-які дані з бінарного формату в base64 чи щось подібне, то краще stdin. Ще один аргумент проти параметрів командного рядка: на деяких системах (зокрема, windows) параметри командного рядка можуть перекодовуватись із втратами (зокрема, з цієї причини java-програми не люблять файлів з кириличною Іі в назві) — якщо зовнішня програма потрібна для обробки даних, чутливих до зміни кодування, краще використати stdin.

Є ще й третій спосіб передачі даних: через змінні середовища.

12

Re: Передати значення змінних у зовнішню програму

P.Y. написав:
Bartash написав:
serge написав:

Цей варіант виходить насправді трохи більш громіздким, ніж другий, але він цікавий хоча б тому, що підходить для зв’язки з зовнішньою програмою, яка не обов’язково написана на С або на мові, де використовується щось аналогічне аргументам main.

Якщо зовнішній програмі треба передавати певні аргументи - не грає ролі, на якій мові вона написана: підхід один. І цей підхід є більш православним, ніж запис до stdin, імго.

Це якщо програма маленька й використовується один раз. А якщо для її запуску й ініціалізації тратиться багато часу, а даних треба обробити багато, то має сенс зробити в ній цикл з повторами вводу даних/виводу результату, а в скрипті не запускати її повторно, а передавати дані одному й тому ж підпроцесу. Крім того, командний рядок може мати обмеження довжини, а кількість даних, прочитаних зі stdin, необмежена — якщо нам треба не додати два числа, а, наприклад, перекодувати якісь невідомо-які дані з бінарного формату в base64 чи щось подібне, то краще stdin. Ще один аргумент проти параметрів командного рядка: на деяких системах (зокрема, windows) параметри командного рядка можуть перекодовуватись із втратами (зокрема, з цієї причини java-програми не люблять файлів з кириличною Іі в назві) — якщо зовнішня програма потрібна для обробки даних, чутливих до зміни кодування, краще використати stdin.

Є ще й третій спосіб передачі даних: через змінні середовища.

Зауваження резонні, приймаються.
Одним словом, все залежить від задачі.

13

Re: Передати значення змінних у зовнішню програму

Те ж саме хотів написати щодо зауважень. До речі, маю запитання: яка роль модуля shlex у прикладі Bartash?