python print()函数实际上做了什么?

时间:2009-12-30 09:20:44

标签: python unicode printing python-2.x

我正在查看此question,并开始想知道print实际上做了什么。

我从未发现如何使用string.decode()string.encode()在python交互式shell中以与打印相同的格式获取unicode字符串“out”。无论我做什么,我都会得到

  1. UnicodeEncodeError或
  2. 带有“\ x ##”表示法的转义字符串......
  3. 这是python 2.x,但我已经尝试修改我的方式并实际调用print():)

    示例:

    >>> import sys
    >>> a = '\xAA\xBB\xCC'
    >>> print(a)
    ª»Ì
    >>> a.encode(sys.stdout.encoding)
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xaa in position 0: ordinal not in range(128)
    >>> a.decode(sys.stdout.encoding)
    u'\xaa\xbb\xcc'
    

    修改

    我为什么这么问?我厌倦了encode()错误,并意识到,因为print可以做到这一点(至少在交互式shell中)。我知道必须是一种方式通过挖掘信息从某个地方使用什么编码来神奇地进行编码正确 ...

    附加信息: 我正在linux2上运行Python 2.4.3(#1,2009年9月3日,15:37:12)[GCC 4.1.2 20080704(Red Hat 4.1.2-46)]

    >>> sys.stdin.encoding
    'ISO-8859-1'
    >>> sys.stdout.encoding
    'ISO-8859-1'
    

    然而,在同一个Linux机器上的结果与Python 2.6.2(r262:71600,2009年9月8日,13:06:43)相同。

4 个答案:

答案 0 :(得分:9)

编辑:(此编辑与上一个编辑之间的重大更改...注意:我在Ubuntu框中使用Python 2.6.4。)

首先,在我第一次尝试回答时,我提供了一些关于printstr的一般信息,我将在下面留下这些信息,以便任何有{{1}更简单问题的人的利益并且对这个问题进行挑战。至于处理OP遇到的问题的新尝试......基本上,我倾向于说这里没有银弹,如果print以某种方式设法理解一个奇怪的字符串文字,那么这不是可重复的行为。我在终端窗口中通过以下与Python的有趣交互得出了这个结论:

print

您是否尝试直接从终端输入ª»Ì?在使用utf-8作为编码的Linux终端上,这实际上是以六个字节读入,然后在>>> print '\xaa\xbb\xcc' �� 方法的帮助下可以看起来像三个unicode字符:

decode

所以,>>> 'ª»Ì' '\xc2\xaa\xc2\xbb\xc3\x8c' >>> 'ª»Ì'.decode(sys.stdin.encoding) u'\xaa\xbb\xcc' 字面只有在将解码为latin-1文字时才有意义(好吧,实际上你可以使用不同的编码同意latin-1相关人物)。至于'\xaa\xbb\xcc''只是在你的情况下工作',它肯定不适合我 - 如上所述。

这是因为当您使用不带print前缀的字符串文字 - 即u而不是"asdf"时 - 结果字符串将使用一些非unicode编码。没有;事实上,字符串对象本身将是编码 - 不知道,并且您将不得不将其视为使用编码x进行编码,以获得正确的x值。这个基本想法引导我:

u"asdf"

注意缺少解码错误和正确的输出(我期望在任何其他方框保持正确)。显然你的字符串文字可以通过Python理解,但不是没有一些帮助。

这有帮助吗? (至少在理解事物是如何工作的时候,如果没有使编码的处理更容易......)


现在有一些有趣的位有一些解释性的价值(希望如此)!这对我来说很好:

a = '\xAA\xBB\xCC'
a.decode('latin1')
# result: u'\xAA\xBB\xCC'
print(a.decode('latin1'))
# output: ª»Ì

跳过解码或编码部分会导致与unicode相关的异常。从理论上讲,这是有道理的,因为需要第一个解码来决定给定字符串中的字符(乍看之下唯一明显的是 bytes ) - Python 3的想法具有(unicode)字符串的字符串和字节,以及字节,突然看起来非常合理),而编码是必需的,以便输出尊重输出流的编码。现在这个

sys.stdout.write("\xAA\xBB\xCC".decode('latin1').encode(sys.stdout.encoding))

也按预期工作,但字符实际上来自键盘,所以实际上是用stdin编码编码的......另外,

sys.stdout.write("ąöî\n".decode(sys.stdin.encoding).encode(sys.stdout.encoding))

返回正确的177(我的输入编码是utf-8),但'\ xc4 \ x85'.encode('latin2')对Python没有任何意义,因为它不知道如何理解' \ xc4 \ x85'以及尝试'ascii'代码的数据是它能做的最好的。


原始答案:

Python文档的

The relevant bit(版本2.6.4)说ord('ą'.decode('utf-8').encode('latin2')) 是打印出print(obj)给出的字符串。我想你可以将它包装在str(obj)的调用中(如在unicode中)以获取unicode字符串 - 或者你可以只使用Python 3并将这种特殊的麻烦换成几个不同的那些。 ; - )

顺便说一句,这表明您可以操纵unicode(str(obj))对象的结果,就像您可以操纵对象上调用print的结果一样,即通过弄乱str } 方法。例如:

__str__

至于class Foo(object): def __str__(self): return "I'm a Foo!" print Foo() 的实际实现,我希望这根本不会有用,但是如果你真的想知道发生了什么......它就在文件中Python源代码中的print(我正在查看2.6.4版本)。搜索以Python/bltinmodule.c开头的行。它实际上完全是直截了当的,没有任何魔力在那里。 : - )

希望这能回答你的问题...但是如果你确实有一个我完全错过的更神秘的问题,请做评论,我会再做一次。另外,我假设我们正在处理Python 2.x;否则我想我不会有有用的评论。

答案 1 :(得分:5)

print()使用sys.stdout.encoding来确定输出控制台可以理解的内容,然后在调用str.encode()时使用此编码。

[编辑]如果你look at the source,它会获得sys.stdout然后调用:

PyFile_WriteObject(PyTuple_GetItem(args, i), file,
                 Py_PRINT_RAW);

我想魔法在Py_PRINT_RAW,但the source只是说:

    if (flags & Py_PRINT_RAW) {
    value = PyObject_Str(v);
    }

这里没有魔力。使用sys.stdout.write(str(item))的参数循环应该可以解决问题。

答案 2 :(得分:2)

>>> import sys
>>> a = '\xAA\xBB\xCC'
>>> print(a)
ª»Ì

此处所有print正在将原始字节写入sys.stdout。字符串a是一个字节字符串,而不是Unicode字符。

  

我为什么这么问?我厌倦了encode()错误并意识到,因为print可以做到(至少在交互式shell中)。我知道必须通过挖掘信息从某个地方使用什么编码来神奇地进行编码......

不,print在这里什么都不做。你把它交给一些字节,它将字节转储到stdout。

要正确使用.encode().decode(),您需要了解字节和字符之间的区别,我担心您必须确定要使用的正确编码。

答案 3 :(得分:0)

import sys

source_file_encoding = 'latin-1' # if there is no -*- coding: ... -*- line

a = '\xaa\xbb\xcc' # raw bytes that represent string in source_file_encoding

# print bytes, my terminal tries to interpret it as 'utf-8'
sys.stdout.write(a+'\n') 
# -> ��

ua = a.decode(source_file_encoding)
sys.stdout.write(ua.encode(sys.stdout.encoding)+'\n')
# -> ª»Ì

请参阅Defining Python Source Code Encodings