2015-06-28 1 views
3

Я пытался поставить питона и рубиновый коды в разговор, и я нашел способы по этой ссылке (http://www.decalage.info/python/ruby_bridge)Python чтение из стандартного ввода зависает при взаимодействии с рубином кодом

Я попробовал последний метод, используя стандартный ввод и стандартный вывод для передачи информации. Я внесла некоторые изменения в исходный код, чтобы он соответствовал python 3.4, но я не уверен, что код, который я изменил, все испортил. Моя программа python всегда зависает при чтении из stdin, и ничего не печаталось. Я не знаком с stdin и stdout, поэтому мне просто интересно, почему это не работает.

Вот мой рубин кода:

$stdin.set_encoding("utf-8:utf-8") 
$stdout.set_encoding("utf-8:utf-8") 

while cmd = $stdin.gets 

    cmd.chop! 
    if cmd == "exit" 
     break 
    else 
     puts eval(cmd) 
     puts "[end]" 
     $stdout.flush 

    end 
end 

Я не уверен, если это возможно, чтобы установить внутреннюю кодировку и внешнюю кодировку, как это. А вот мои питона коды:

from subprocess import Popen, PIPE, STDOUT 

print("Launch slave process...") 
slave = Popen(['ruby', 'slave.rb'], stdin=PIPE, stdout=PIPE, stderr=STDOUT) 

while True: 
    line = input("Enter expression or exit:") 
    slave.stdin.write((line+'\n').encode('UTF-8')) 
    result = [] 
    while True: 
     if slave.poll() is not None: 
      print("Slave has terminated.") 
      exit() 

     line = slave.stdout.readline().decode('UTF-8').rstrip() 
     if line == "[end]": 
      break 
     result.append(line) 
    print("result:") 
    print("\n".join(result)) 

Когда я пытаюсь запустить сценарий питона, ввод «3 * 4» и нажмите Enter, ничего не показывает, пока я не сломал процесс вручную с кодом выхода 1 и KeyboardInterrupt Exception. Я долгое время боролся с этой проблемой, и я не знаю, что пошло не так ... Заранее благодарим за любую возможную помощь!

ответ

2

Разница заключается в том, что bufsize=-1 по умолчанию в Python 3.4, и поэтому slave.stdin.write() не отправляет линию на подпроцесс ruby немедленно. Быстрое решение - добавить slave.stdin.flush() звонок.

#!/usr/bin/env python3 
from subprocess import Popen, PIPE 

log = print 
log("Launch slave process...") 
with Popen(['ruby', 'slave.rb'], stdin=PIPE, stdout=PIPE, 
      bufsize=1, universal_newlines=True) as ruby: 
    while True: 
     line = input("Enter expression or exit:") 
     # send request 
     print(line, file=ruby.stdin, flush=True) 
     # read reply 
     result = [] 
     for line in ruby.stdout: 
      line = line.rstrip('\n') 
      if line == "[end]": 
       break 
      result.append(line) 
     else: # no break, EOF 
      log("Slave has terminated.") 
      break 
     log("result:" + "\n".join(result)) 

Он использует universal_newlines=True включить режим текста. Он использует locale.getpreferredencoding(False) для декодирования байтов. Если вы хотите принудительно выполнить кодировку utf-8, независимо от настроек локали, отпустите universal_newlines и заверните трубы в io.TextIOWrapper(encoding="utf-8") (code example -- it also shows the proper exception handling for the pipes).

+0

Он отлично работает. Благодаря! –