为什么 Python 2.7 的输出与 Python 3.10 的输出不同?
Why is the output different with Python 2.7 than Python 3.10?
$ /usr/bin/python2 simple.py 200 > out2.pbm
$ /opt/src/Python-3.10.1/bin/python3 simple.py 200 > out3.pbm
$ cmp out2.pbm out3.pbm
out2.pbm out3.pbm differ: byte 304, line 3
python2 输出是正确的。
python3 输出不正确。
这里是a correct .pbm output file。
simple.py 是
import sys
w = h = x = y = bit_num = 0
byte_acc = 0
i = 0; iterations = 50
limit = 2.0
Zr = Zi = Cr = Ci = Tr = Ti = 0.0
w = int(sys.argv[1])
h = w
sys.stdout.write("P4\n%d %d\n" % (w, h))
for y in range(h):
for x in range(w):
Zr = Zi = 0.0
Cr = (2.0 * x / w - 1.5); Ci = (2.0 * y / h - 1.0)
for i in range(iterations):
Tr = Zr*Zr - Zi*Zi + Cr
Ti = 2*Zr*Zi + Ci
Zr = Tr; Zi = Ti
if Zr*Zr+Zi*Zi > limit*limit:
break
if Zr*Zr+Zi*Zi > limit*limit:
byte_acc = (byte_acc << 1) | 0x00
else:
byte_acc = (byte_acc << 1) | 0x01
bit_num += 1
if bit_num == 8:
sys.stdout.write(chr(byte_acc))
byte_acc = 0
bit_num = 0
elif x == w - 1:
byte_acc = byte_acc << (8-w%8)
sys.stdout.write(chr(byte_acc))
byte_acc = 0
bit_num = 0
什么变化可能导致不同的输出?
我无法在 Python 3.10.1(Windows,64 位)下 运行:
**Traceback (most recent call last):
File ... simple.py", line 39, in <module>
sys.stdout.write(chr(byte_acc))
File ... \lib\encodings\cp1252.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\x80' in position 0: character maps to <undefined>
如果我将 chr()
的 2 个实例更改为 str()
(以便它打印出字节的十进制值的字符串表示形式),它会在 3.10.1 和下产生相同的输出2.7.11.
因此,无论您的 Python 在 Python 下为 sys.stdout
使用任何默认的 Unicode 编码方案,您都会被烧毁 3.
如果我像这样设置一个 envar(语法可能与您的 OS 不同):
set PYTHONIOENCODING=latin-1
然后两个 Python 使用 chr()
产生相同的输出。
一种方式
这是“修复它”的一种方法:
import sys
from sys import stdout
if hasattr(stdout, "buffer"): # Python >= 3
def putbyte(b):
assert 0 <= b < 256
stdout.buffer.write(bytes([b]))
else: # before Python 3
def putbyte(b):
assert 0 <= b < 256
stdout.write(chr(b))
然后更改您的代码以使用 putbyte(byte_acc)
而不是当前的 sys.stdout.write(chr(byte_acc))
。
但这还不够。自己写入内部缓冲区也使您负责跨用途的缓冲区管理。当前
之后
sys.stdout.write("P4\n%d %d\n" % (w, h))
您还需要添加
sys.stdout.flush()
在添加额外的输出字节之前将输出字符串放入缓冲区。
$ /usr/bin/python2 simple.py 200 > out2.pbm
$ /opt/src/Python-3.10.1/bin/python3 simple.py 200 > out3.pbm
$ cmp out2.pbm out3.pbm
out2.pbm out3.pbm differ: byte 304, line 3
python2 输出是正确的。 python3 输出不正确。
这里是a correct .pbm output file。
simple.py 是
import sys
w = h = x = y = bit_num = 0
byte_acc = 0
i = 0; iterations = 50
limit = 2.0
Zr = Zi = Cr = Ci = Tr = Ti = 0.0
w = int(sys.argv[1])
h = w
sys.stdout.write("P4\n%d %d\n" % (w, h))
for y in range(h):
for x in range(w):
Zr = Zi = 0.0
Cr = (2.0 * x / w - 1.5); Ci = (2.0 * y / h - 1.0)
for i in range(iterations):
Tr = Zr*Zr - Zi*Zi + Cr
Ti = 2*Zr*Zi + Ci
Zr = Tr; Zi = Ti
if Zr*Zr+Zi*Zi > limit*limit:
break
if Zr*Zr+Zi*Zi > limit*limit:
byte_acc = (byte_acc << 1) | 0x00
else:
byte_acc = (byte_acc << 1) | 0x01
bit_num += 1
if bit_num == 8:
sys.stdout.write(chr(byte_acc))
byte_acc = 0
bit_num = 0
elif x == w - 1:
byte_acc = byte_acc << (8-w%8)
sys.stdout.write(chr(byte_acc))
byte_acc = 0
bit_num = 0
什么变化可能导致不同的输出?
我无法在 Python 3.10.1(Windows,64 位)下 运行:
**Traceback (most recent call last):
File ... simple.py", line 39, in <module>
sys.stdout.write(chr(byte_acc))
File ... \lib\encodings\cp1252.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\x80' in position 0: character maps to <undefined>
如果我将 chr()
的 2 个实例更改为 str()
(以便它打印出字节的十进制值的字符串表示形式),它会在 3.10.1 和下产生相同的输出2.7.11.
因此,无论您的 Python 在 Python 下为 sys.stdout
使用任何默认的 Unicode 编码方案,您都会被烧毁 3.
如果我像这样设置一个 envar(语法可能与您的 OS 不同):
set PYTHONIOENCODING=latin-1
然后两个 Python 使用 chr()
产生相同的输出。
一种方式
这是“修复它”的一种方法:
import sys
from sys import stdout
if hasattr(stdout, "buffer"): # Python >= 3
def putbyte(b):
assert 0 <= b < 256
stdout.buffer.write(bytes([b]))
else: # before Python 3
def putbyte(b):
assert 0 <= b < 256
stdout.write(chr(b))
然后更改您的代码以使用 putbyte(byte_acc)
而不是当前的 sys.stdout.write(chr(byte_acc))
。
但这还不够。自己写入内部缓冲区也使您负责跨用途的缓冲区管理。当前
之后sys.stdout.write("P4\n%d %d\n" % (w, h))
您还需要添加
sys.stdout.flush()
在添加额外的输出字节之前将输出字符串放入缓冲区。