有没有办法更改Python的open()默认文本编码?
我可以在不同平台上改变默认的 open()
(io.open()
在 2.7 版本中) 文本编码吗?
这样我就不需要每次都写 open(...,encoding='utf-8')
了。
在文本模式下,如果没有指定 encoding,那么使用的编码会依赖于平台:会调用
locale.getpreferredencoding(False)
来获取当前的地区编码。
虽然文档没有说明如何 设置 首选编码。这个功能在 locale
模块里,所以我需要改变地区设置吗?有没有可靠的跨平台方法来设置 UTF-8 地区?这会影响到除了默认文本文件编码以外的其他东西吗?
或者说,改变地区设置是危险的(可能会导致问题),我应该使用像这样的自定义封装:
def uopen(*args, **kwargs):
return open(*args, encoding='UTF-8', **kwargs)
5 个回答
我建议不要更改locale
,因为这可能会对你系统的其他部分产生很多意想不到的影响。open
是一个系统级的函数调用,所以它的设置可能会影响到其他地方,至少会影响到使用同一个Python安装的其他Python程序。你的封装看起来很合适,结构也很简洁,便于移植,应该是正确的解决方案。
也许PEP 540(UTF-8模式)正是你需要的:
https://peps.python.org/pep-0540/
使用 -Xutf8
python.exe -Xutf8 -c "open('tmp.txt', 'w').write('天地玄黄0123'); print(open('tmp.txt').read())"
在PowerShell中使用 PYTHONUTF8
$env:PYTHONUTF8=1; python.exe -c "open('tmp.txt', 'w').write('天地玄黄0123'); print(open('tmp.txt').read())"
在命令提示符(Cmd)中使用 PYTHONUTF8
set PYTHONUTF8=1&& python.exe -c "open('tmp.txt', 'w').write('天地玄黄0123'); print(open('tmp.txt').read())"
在Bash中使用 PYTHONUTF8
PYTHONUTF8=1 python -c "open('tmp.txt', 'w').write('天地玄黄0123'); print(open('tmp.txt').read())"
你还可以执行 setx PYTHONUTF8 1
来将其保存为用户级别的环境变量。
如果你真的需要改变默认的编码方式,你可以替换掉内置的 open
函数。
original_open = __builtins__.open
def uopen(*args, **kwargs):
if "b" not in (args[1] if len(args) >= 2 else kwargs.get("mode", "")):
kwargs.setdefault("encoding", "UTF-8")
return original_open(*args, **kwargs)
__builtins__.open = uopen
我在看到关于替换 print
的邮件后,写了并测试了这个代码片段,具体可以参考这封邮件。
你可以设置编码……不过这样做有点 hacky(不太正规)。
import sys
sys.getdefaultencoding() #should print your default encoding
sys.setdefaultencoding("utf8") #error ... no setdefaultencoding ... but...
reload(sys)
sys.setdefaultencoding("utf8") #now it succeeds ...
我建议你这样做:
main_script.py
import __builtin__
old_open = open
def uopen(*args, **kwargs):
return open(*args, encoding='UTF-8', **kwargs)
__builtin__.open = uopen
这样你在任何地方调用 open
时,它都会使用 utf8 编码……不过如果你明确指定编码,可能会出现错误。
或者每次打开文件时都明确传递编码,或者使用你的封装方法……
Python 的一般原则是明确比隐含好,这意味着在打开文件时,正确的做法是明确声明你的编码……
不要随便改变地区设置或首选编码,因为:
- 这可能会影响你代码的其他部分(或者你正在使用的库);
- 这样会让人不清楚你的代码是依赖于
open
使用特定编码的。
相反,使用一个简单的包装函数:
from functools import partial
open_utf8 = partial(open, encoding='UTF-8')
如果需要的话,你还可以为所有关键字参数设置默认值。