Как зафиксировать вывод команды run в python3 в python2? - PullRequest
1 голос
/ 29 мая 2019

У меня есть файл, который подключается к базе данных и получает результат. Теперь файл должен быть запущен с использованием python 3, а мой проект использует python 2.7. Поэтому я запускаю файл как командную строку, используя модуль subprocess. Вот как я называю файл.

import subprocess
import ast

def execute_python3(param):
    param = param.replace("\\", "")
    param = "\"" + param + "\""

    cmd = "python3 " + "get_db_result.py" + " " + param

    result = subprocess.check_output(cmd, shell=True)
    return ast.literal_eval(result)

execute_python3(sql_query)

Здесь в команде я передаю sql-запрос в файл get_db_result.

Файл get_db_result.py выглядит примерно так

import sys
def get_result():
    param = sys.argv[1]
    '''
    Logic to get result from db
    '''
    result = db_output
    print(result)

if __name__ == "__main__":
    get_result()

Теперь проблема заключается в том, что когда я выбираю вывод из базы данных, мне нужно сделать print для вывода, который будет захвачен модулем subprocess. Это затрудняет анализ выходных данных, которые будут использоваться программой для дальнейшей работы. Например, когда я получаю вывод, подобный этому

"[(u'Delhi', 20199330), (u'Mumbai', 134869470), (u'Kolkata', 6678446)]"

Это строковый список кортежей, который можно преобразовать в список кортежей, выполнив что-то вроде ast.literal_eval(result)

Но иногда я получаю вывод, как этот

"[(datetime.date(2019, 5, 27), 228.168093587), (datetime.date(2019, 5, 28), 228.834493641)]"

Здесь ast не понимает datetime. Даже json.loads() не работает на этом.

Как мне захватить вывод из файла, не используя print, и просто вернуть его обратно к subprocess как есть. Это вообще возможно?

1 Ответ

1 голос
/ 29 мая 2019

Вам необходимо сериализовать и десериализовать данные на обоих концах.Самое простое решение - использовать модуль Python pickle и надеяться, что типы, которые сериализуются на стороне Python 3, достаточно похожи на типы на десериализационной стороне Python 2.Необходимо указать используемый протокол на отправляющей стороне для версии, понятной получающей стороне:

Получатель с более безопасным вызовом подпроцесса (между процессами оболочки нет):

#!/usr/bin/env python
import pickle
import subprocess


def execute_python3(param):
    result = subprocess.check_output(['python3', 'get_db_result.py', param])
    return pickle.loads(result)


def main():
    execute_python3(sql_query)


if __name__ == '__main__':
    main()

Отправитель, явно выбирая протокол pickle, все еще понимаемый Python 2:

#!/usr/bin/env python3
import sys
import pickle


def get_result():
    param = sys.argv[1]
    '''
    Logic to get result from db
    '''
    result = db_output
    pickle.dump(result, sys.stdout.buffer, protocol=2)


if __name__ == '__main__':
    get_result()

Если это не сработает из-за различий в (де) сериализованных объектах между Python 2 и 3, вам придется обратиться к явному(де) сериализовать данные, например, в JSON, как предложено в комментарии от Jay.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...