2014-10-06 3 views
2

У меня есть два сценария python: object_generator.py, который распевает данный объект и печатает его. Другой скрипт object_consumer.py выбирает вывод первого скрипта через subprocess.communicate и пытается разложить его с помощью pickle.loads. У меня возникли проблемы с этой простой работой. Это мой код:Передача вывода маринованного объекта между скриптами python через subprocess.communicate

object_generator.py

import pickle 
import base64 

o = {'first':1,'second':2,'third':3,'ls':[1,2,3]} 
d = pickle.dumps(o) 
print(d) 

#Various Approaches I had tried, none of which worked. Ignore this part. 
#s = base64.b64decode(d) 
#encoded_str = str(d).encode('ascii') 
#print('encoded str is :') 
#print(encoded_str) 
#decoded_str = encoded_str.decode('ascii') 
#print('decoded str is :') 
#print(decoded_str) 
#unpickled_obj = pickle.loads(bytes(decoded_str)) 
#print(unpickled_obj) 
#print(type(d)) 
#print(codecs.decode(d)) 

object_consumer.py

import pickle 
import subprocess 
import os 

dr = '"' + os.path.dirname(os.path.abspath(__file__)) + '\\object_generator.py"' 

cmd = 'python -u ' + dr 

proc = subprocess.Popen(cmd,stdout=subprocess.PIPE) 

try: 
    outs, errs = proc.communicate(timeout=15) 
except TimeoutExpired: 
    proc.kill() 
    outs, errs = proc.communicate() 

# 'out' at this point is something like this : 
# b"b'\\x80\\x03}q\......x05K\\x03u.'\r\n" 
# DO SOMETHING WITH outs to get back the bytes which can then be 
# unpickled using pickle.loads 

obj = pickle.loads(outs) 
print(obj) 

Очевидно, что мне нужно сдирать трейлинг \ г \ п, которое легко, но то, что должно быть сделано следующий?

+0

делает ваши усилия на цель, имеющая работу сценария, используя й очень заданного 'subprocess' модуль метод' .communicate() ', или вы открыты для реализовать python-процесс-коммуникационное решение, используя «подпроцесс» или другие средства? – user3666197

+0

Я попробовал subprocess.check_ouput, а затем перешел на связь, когда это не сработало, но у меня нет ограничений на использование связи. Я был бы признателен за любой альтернативный метод, а также объяснение того, что в этом нет. –

+0

Всегда полезно отделить проблему от процесса к процессу связи из проблем представления/кодирования/кодирования/кадрирования полезной нагрузки. Для первого может оказаться полезным получить обзор быстрого и масштабируемого обмена сообщениями между процессами ** ZeroMQ ** (со многими портами, включая python), где вы получаете все полномочия под своим контролем, чтобы быть в состоянии для соответствия архетипов коммуникации в распределенной параллельной обработке потребностей Проекта. – user3666197

ответ

2

Здесь есть несколько проблем. Сначала вы печатаете объект bytes в object_generator.py. В Python 3.x это приведет к выходу str(obj), что означает, что печатается b'yourbyteshere'. Вы не хотите, чтобы ведущий b' или задний '. Чтобы исправить это, вам нужно закодировать объект bytes как строку. pickle использует кодировку 'latin-1', поэтому мы можем использовать ее для декодирования объекта bytes на str. Другая проблема заключается в том, что кодировка Windows по умолчанию для sys.stdout фактически не поддерживает печать декодированных строк pickle. Итак, нам нужно изменить кодировку по умолчанию для sys.stdout * до 'latin-1', поэтому строка перейдет к родительскому процессу с правильной кодировкой.

import pickle 
import base64 
import codecs 

o = {'first':1,'second':2,'third':3,'ls':[1,2,3]} 
d = pickle.dumps(o) 
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='latin-1') 
print(d.decode('latin-1'), end='', flush=True) # end='' will remove that extra \r\n 

Внесите эти изменения, и он должен работать нормально.

Edit:

Другим вариантом было бы установить переменную PYTHONIOENCODING окружения 'latin-1' от родительского процесса:

env = os.environ.copy() 
env['PYTHONIOENCODING'] = 'latin-1' 
proc = subprocess.Popen(['python3', 'async2.py'] ,stdout=subprocess.PIPE, env=env) 

* См this question для получения дополнительной информации об изменении sys.stdout кодирования в Python 3. Здесь упоминаются оба подхода, которые я показываю здесь.

+0

Это сработало. Я вижу, что вы отменили свой ответ и повторно отправили исправление. Цените свое терпение и проблемы. –

+2

@rusticbit Да, мой оригинальный ответ отлично работал на Linux, но не работал в Windows. Я забыл о различии в кодировке по умолчанию 'sys.stdout' в Windows. – dano

+1

@rusticbit Я обновил свой ответ, чтобы использовать модуль 'io' вместо' codecs', поскольку модуль 'io' [обычно должен быть предпочтительнее модуля' codecs'] (https://mail.python.org /pipermail/python-list/2010-December/593460.html). Я также добавил способ решить проблему из родительского скрипта. – dano

1

Я не предлагаю использовать рассол между вашим основным файлом и незнакомым внешним, так как он требует, чтобы исходные классы были живыми, а также медленными.

Я использовал модуль Маршалла, надеюсь, что это поможет вам сэкономить время: https://github.com/jstar88/pyCommunicator

Смежные вопросы