Python 2 和 3 兼容的字符串文件编写器
Python 2 and 3 compatible string file writer
我创建了一个 python 上下文管理器,它捕获所有输出 sys.stdout,例如使用 print(),并将其写入文件。
问题是我无法让它同时适用于 python 2.7 和 3.6。
上下文管理器内部使用
self.file_writer = open(self.log_file, 'w', encoding='utf8')
但是当我 运行 它在 Python 2.7 中时,那么
print(u"a test string")
导致错误消息:
write() argument 1 must be unicode, not str
即使字符串显然是 unicode。
如果我将文件更改为
self.file_writer = open(self.log_file, 'wb')
那么它在 Python 2.7 中有效,但在 3.6 中无效。
我需要做什么才能使其适用于任何 python 版本?
以下为经理摘录:
PATH_PREFIX = "some/path/"
class manager:
def __init__(self):
self.log_file = os.path.join(PATH_PREFIX, 'log.txt')
def __enter__(self):
# create a file for logging
self.log_file_stream = open(self.log_file, 'w', encoding='utf8')
self.log_file_stream.__enter__()
# redirect stdout to this file
self.previous_stdout = sys.stdout
sys.stdout = self.log_file_stream
return self
def __exit__(self, etype, value, exception_traceback):
# stop redirecting stdout to the log file
sys.stdout = self.previous_stdout
# close the log file
self.log_file_stream.__exit__()
sys.stdout
在 Python 2 中应该是一个字节流,但是在 Python 3 中是一个 Unicode 流。 print
for Python 2 编码在写入 stdout 之前将 Unicode 字符串转换为字节字符串,但您已将 sys.stdout
覆盖为 Python 2 和 Python 3 中的 Unicode 流。
覆盖sys.stdout
时,您需要为Python 2提供字节流,但为Python 3提供Unicode流。您可以使用sys.version_info.major
来决定支持哪一个。
阅读其他答案并了解到 python 的现有库无法做到这一点后,我编写了一个上下文管理器来替换 open()。这有点 hacky,但它完成了工作。
它可能可以通过显式检查 python 版本而不是使用 hasattr() 来改进,但我在写这篇文章时并不知道这一点:
class open_properly(object):
"""
This is a file writer that doesn't complain about unicode/string mismatches.
It works for both python 2.7 and 3+.
"""
def __init__(self, file_path):
super(open_properly, self).__init__()
self.file_path = file_path
def __enter__(self):
self.file_writer = open(self.file_path, 'w', encoding='utf8')
self.file_writer.__enter__()
return self
def write(self, s):
if not isinstance(s, string_types):
raise ValueError("the text to print must be a valid string type")
# make sure it's unicode (important for python 2)
if isinstance(s, str):
if hasattr(s, 'decode'):
s = s.decode('utf-8')
# write unicode to file
self.file_writer.write(s)
def __exit__(self, exc_type, exc_val, exc_tb):
return self.file_writer.__exit__(exc_type, exc_val, exc_tb)
我创建了一个 python 上下文管理器,它捕获所有输出 sys.stdout,例如使用 print(),并将其写入文件。
问题是我无法让它同时适用于 python 2.7 和 3.6。
上下文管理器内部使用
self.file_writer = open(self.log_file, 'w', encoding='utf8')
但是当我 运行 它在 Python 2.7 中时,那么
print(u"a test string")
导致错误消息:
write() argument 1 must be unicode, not str
即使字符串显然是 unicode。
如果我将文件更改为
self.file_writer = open(self.log_file, 'wb')
那么它在 Python 2.7 中有效,但在 3.6 中无效。
我需要做什么才能使其适用于任何 python 版本?
以下为经理摘录:
PATH_PREFIX = "some/path/"
class manager:
def __init__(self):
self.log_file = os.path.join(PATH_PREFIX, 'log.txt')
def __enter__(self):
# create a file for logging
self.log_file_stream = open(self.log_file, 'w', encoding='utf8')
self.log_file_stream.__enter__()
# redirect stdout to this file
self.previous_stdout = sys.stdout
sys.stdout = self.log_file_stream
return self
def __exit__(self, etype, value, exception_traceback):
# stop redirecting stdout to the log file
sys.stdout = self.previous_stdout
# close the log file
self.log_file_stream.__exit__()
sys.stdout
在 Python 2 中应该是一个字节流,但是在 Python 3 中是一个 Unicode 流。 print
for Python 2 编码在写入 stdout 之前将 Unicode 字符串转换为字节字符串,但您已将 sys.stdout
覆盖为 Python 2 和 Python 3 中的 Unicode 流。
覆盖sys.stdout
时,您需要为Python 2提供字节流,但为Python 3提供Unicode流。您可以使用sys.version_info.major
来决定支持哪一个。
阅读其他答案并了解到 python 的现有库无法做到这一点后,我编写了一个上下文管理器来替换 open()。这有点 hacky,但它完成了工作。
它可能可以通过显式检查 python 版本而不是使用 hasattr() 来改进,但我在写这篇文章时并不知道这一点:
class open_properly(object):
"""
This is a file writer that doesn't complain about unicode/string mismatches.
It works for both python 2.7 and 3+.
"""
def __init__(self, file_path):
super(open_properly, self).__init__()
self.file_path = file_path
def __enter__(self):
self.file_writer = open(self.file_path, 'w', encoding='utf8')
self.file_writer.__enter__()
return self
def write(self, s):
if not isinstance(s, string_types):
raise ValueError("the text to print must be a valid string type")
# make sure it's unicode (important for python 2)
if isinstance(s, str):
if hasattr(s, 'decode'):
s = s.decode('utf-8')
# write unicode to file
self.file_writer.write(s)
def __exit__(self, exc_type, exc_val, exc_tb):
return self.file_writer.__exit__(exc_type, exc_val, exc_tb)