2015-02-18 3 views
0

Вот мой код:печати только содержимое строки

#! /usr/bin/env python3 
import subprocess 
a = subprocess.check_output('echo -n "hello world!"',shell=True) 
print("a="+str(a)) 

выход:

a=b'hello world!' 

Если я включаю аргумент universal_newlines=True в вызове check_output, то я получаю желаемый результат:

a=hello world! 

Для лучшего понимания загадочного мира программирования с текстом в e modern (Unicode) возраст, я хотел бы знать, как создать второй вывод, не указав universal_newlines=True. Другими словами, какую функцию я вызываю для преобразования a так, чтобы она выдавала желаемый результат.

Рабочий пример проделан долгий путь. Подробные объяснения хороши, но они, как правило, немного запутывают непосвященных - возможно, из-за использования перегруженной терминологии, возможно, из-за различий между Python2 и Python3 или, может быть, только потому, что мне очень редко приходится думать о кодировании текста в моя работа - большинство инструментов, с которыми я работаю, не требуют специальной обработки.

Также: Я считаю, что первый выход имеет тип bytes, но каков тип второго выхода? Мое предположение - str с кодировкой UTF-8.

+0

Вы пробовали декодировать выход? –

+0

@ IgnacioVazquez-Abrams: Конечно, я попытался понять это, но мои первые несколько догадок не выходили за рамки. Я надеюсь, кто-то покажет мне, как это сделать. Что такое синтаксис? Каковы типы данных? и т. д. Я уверен, что это очень легко для людей, которые уже знают, как это сделать. Надеюсь, скоро я стану одним из этих людей. :) – nobar

+0

Теперь, когда я знаю, что все называется, мне удалось найти [dup] (http://stackoverflow.com/questions/606191/convert-bytes-to-a-python-string). Основываясь на количестве полученных запросов, я думаю, справедливо утверждать, что документация для модуля подпроцесса может предоставить несколько советов по использованию, чтобы быть проще для обычного пользователя Python. – nobar

ответ

0

также: Я считаю, что первый выход имеет тип bytes, но что тип второго выхода? Моя догадка str с кодировкой UTF-8 .

Закрыть, но не совсем верно. В Python3 тип str индексируется Unicode с кодовыми точками (обратите внимание, что кодовые точки обычно, но не всегда, имеют соответствие 1: 1 с воспринимаемыми пользователем символами). Поэтому базовый код абстрагируется при использовании типа str - считайте его незакодированным, хотя это принципиально не тот случай. Это тип bytes, который индексируется как простой массив байтов и поэтому должен использовать конкретный encoding. В этом случае (как и в большинстве подобных случаев) ASCII будет достаточным для декодирования того, что было создано сценарием подпроцесса.

python2 имеет различные значения по умолчанию для интерпретации str типа (see here), так строковые литералы будут представлены по-разному в этой версии языка (эта разница может быть большим камнем преткновения при исследовании обработки текста).

Как человек, который в основном используется C++, я нашел следующий чрезвычайно поучительно о практическом хранении, кодировании и индексации текста Unicode: How do I use 3 and 4-byte Unicode characters with standard C++ strings?


Таким образом, ответ на первую часть вопрос заключается в bytes.decode():

a = a.decode('ascii') ## convert from `bytes` to 'str' type 

хотя просто используя

a = a.decode() ## assumes UTF-8 encoding 

обычно будет давать те же результаты, что и ASCII - это подмножество UTF-8.

В качестве альтернативы, вы можете использовать str() так:

a = str(a,encoding='ascii') 

, но обратите внимание, что здесь кодировка должна быть указана, если вы хотите «содержимое только» представление - в противном случае он будет на самом деле построить str тип, который внутренне содержит символы кавычек (включая префикс «b»), что и происходит в первом выпуске, указанном в вопросе.


subprocess.check_output обрабатывает данные в двоичном режиме (возвращение сырой последовательность байт) по умолчанию, но зашифрованное аргумент universal_newlines=True в основном говорит его декодировать строку и представить его в виде текста (с использованием str type). Это преобразование в тип str необходимо (в Python3), если вы хотите отобразить вывод (и «только содержимое») с помощью функции print Python.

Самое смешное в этом преобразовании заключается в том, что для этих целей он действительно ничего не делает с данными. Что происходит под капотом, это деталь реализации, но если данные являются ASCII (как это очень типично для этого типа программы), он по существу просто копируется из одного места в другое без какого-либо значимого перевода. Операция - это всего лишь hoop jumping, чтобы изменить тип данных - и, казалось бы, бессмысленный характер операции еще более запутывает большее видение обработки текста Python (для непосвященных). Кроме того, поскольку the docs не делают тип возвращаемых данных явным (по имени), трудно даже знать, с чего начать поиск соответствующей функции преобразования.

+0

Показать тип объекта: 'print (" a = ["+ str (a) +"], type = "+ str (type (a)))' – nobar

+0

У меня, вероятно, не было бы проблем и никогда не спрашивал этот вопрос, если они просто сделали default_newlines = True' значением по умолчанию. Если ваш подпроцесс возвращает не-ASCII Unicode (редкий случай в моем опыте), то вы были бы счастливы разобраться с этим процессом преобразования. Если ваш подпроцесс возвращает нетекстовый двоичный код, тогда режим двоичного возврата будет хорошим, но, возможно, его следует назвать как таковым. – nobar

+0

С положительной стороны я могу наконец сказать, что я на самом деле запрограммирован с помощью Unicode - хотя он использовался только для [подмножества ASCII] (http://stackoverflow.com/questions/19212306/difference-between-ascii- и-unicode) и не служили реальной цели. – nobar

2

Как первоначально подразумевал комментарием Игнасио, вы могли бы использовать decode:

>>> a = b"hello world!" 
>>> print("a="+str(a)) 
a=b'hello world!' 
>>> print("a="+a.decode()) 
a=hello world! 
+0

Очень полезно - спасибо, что указал мне в правильном направлении. – nobar

1

От subprocess.check_output() docs:

По умолчанию эта функция будет возвращать данные в виде закодированных байт. Фактическое кодирование выходных данных может зависеть от вызываемой команды , поэтому часто требуется декодирование текста на уровне приложения .

Такое поведение может быть отменено путем установкиuniversal_newlines к True , как описано ниже в Frequently Used Arguments.

Если вы перейдете по ссылке к Frequently Used Arguments; он описывает то, что делает universal_newlines=True:

universal_newlines Если это False объекты файл STDIN, STDOUT и STDERR будет открыт бинарных потоков, и ни одна строка заканчивается преобразование не делается.

universal_newlines Если это True эти объекты файл будет открыт потоки текста в режиме универсального Newlines, используя кодировку, возвращенное locale.getpreferredencoding(False). Для stdin символы окончания строки '\n' на входе будут преобразованы в разделитель строк по умолчанию os.linesep. Для stdout и stderr все окончания линии на выходе будут быть преобразованы в '\n'. Для получения дополнительной информации см. Документацию io.TextIOWrapper class, когда аргумент новой строки для своего конструктора равен None.

Для получения дополнительной информации вы можете посмотреть io.TextIOWrapper() documentation.

Чтобы запустить echo -n "hello world!" команду оболочки и возвратить текст без check_output() и без использования universal_newlines=True:

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

charset = locale.getpreferredencoding(False) 
with Popen(['echo', 'Hello world!'], stdout=PIPE) as process: 
    output = process.communicate()[0].decode(charset).strip() 

Вот couple of code examples, которые показывают how subprocess pipes and TextIOWrapper class could be used together.

Чтобы понять, что такое текст и что такое двоичные данные в Python, читайте Unicode HOWTO. Вот самая важная часть: в Python есть два основных типа строк: bytestrings (последовательность байтов), которые представляют двоичные данные и строки Unicode (последовательность кодовых точек Unicode), которые представляют собой текст, читаемый человеком. Простое преобразование одного в другое (☯):

unicode_text = bytestring.decode(character_encoding) 
bytestring = unicode_text.encode(character_encoding) 
+0

Эти документы были первым, что я прочитал (вот как я догадался попробовать «universal_newlines = True»). Но, честно говоря, многое из этого было по моей голове изначально, потому что я не знал, как вся терминология переведена на типы данных (которую я теперь знаю, может быть либо «байтами», либо «str») и вызовами функций (в частности он не говорит мне, что я должен, вероятно, просто называть 'decode()', хотя данные действительно не закодированы). – nobar

+0

... Кроме того, описание (и имя) 'universal_newlines' напрямую не соответствует чему-либо в моем предыдущем опыте. Похоже, что я описываю то, что я обычно рассматриваю как текстовые и двоичные режимы ввода-вывода, но это, как правило, NOP для Linux-систем, поэтому я не счел это слишком значимым. То, что я не вижу в этих документах, - это четкая документация о том, что 'universal_newlines = True' изменяет тип возврата с' bytes' на 'str'. ... Но в этом ответе есть много хороших данных - спасибо! – nobar

+0

@nobar: Я (почти) уверен, что подпроцесс «docs», не говорите, что вы вызываете метод .strip() ', если хотите удалить ведущее/конечное пустое пространство из вывода. В модуле 'subprocess' используются типы' bytes', 'str', но обучение по поводу' bytes.decode() 'не является его обязанностью. Фраза * текстовые потоки * подразумевает, что результатом является 'str' (последний абзац является общим знанием в Python - вы не должны ожидать, что подпроцесс вас научит этому). Да, «universal_newlines» не предлагает для меня «текстовый режим» - кажется хорошим компромиссом, если вам нужно написать код с одним источником Python 2/3. – jfs

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