Car*_*han 5 python python-2to3 python-3.x
将代码从 Python 2 转换为 Python 3 时,一个问题是测试字符串和字节是否相等时的行为发生了变化。例如:
foo = b'foo'
if foo == 'foo':
print("They match!")
Run Code Online (Sandbox Code Playgroud)
在 Python 3 上不打印任何内容,并且“它们匹配!” 在 Python 2 上。在这种情况下很容易发现,但在许多情况下,检查是对可能已在其他地方定义的变量执行的,因此没有明显的类型信息。
我想让 Python 3 解释器在字符串和字节之间进行相等测试时给出错误,而不是默默地得出它们不同的结论。有什么办法可以做到这一点吗?
(已编辑:修复一个问题,即我错误地建议修改__eq__实例会影响==@user2357112supportsMonica 所建议的评估)。
通常,您可以通过覆盖__eq__您想要保护的类型的方法来做到这一点。不幸的是,对于内置类型,尤其是str和,这无法完成bytes,因此代码如下:
foo = b'foo'
bytes.__eq__ = ... # a custom equal function
# str.__eq__ = ... # if it were 'foo' == foo (or `type(foo)`)
if foo == 'foo':
print("They match!")
Run Code Online (Sandbox Code Playgroud)
只会抛出:
Run Code Online (Sandbox Code Playgroud)AttributeError: 'bytes' object attribute '__eq__' is read-only
您可能需要使用以下内容手动保护比较:
def str_eq_bytes(x, y):
if isinstance(x, str) and isinstance(y, bytes):
raise TypeError("Comparison between `str` and `bytes` detected.")
elif isinstance(x, bytes) and isinstance(y, str):
raise TypeError("Comparison between `bytes` and `str` detected.")
Run Code Online (Sandbox Code Playgroud)
用途如下:
foo = 'foo'
if str_eq_bytes(foo, 'foo') or foo == 'foo':
print("They match!")
# They match!
foo = 'bar'
if str_eq_bytes(foo, 'foo') or foo == 'foo':
print("They match!")
# <nothing gets printed>
foo = b'foo'
if str_eq_bytes(foo, 'foo') or foo == 'foo':
print("They match!")
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)TypeError: Comparison between `bytes` and `str` detected.
另一种选择是在您自己的 Python fork 中进行 hack 并覆盖__eq__. 请注意,Pypy 也不允许您覆盖内置类型的方法。
有一个选项,-b您可以传递给Python解释器,使其在比较字节/字符串时发出警告或错误。
> python --help
usage: /bin/python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
-b : issue warnings about str(bytes_instance), str(bytearray_instance)
and comparing bytes/bytearray with str. (-bb: issue errors)
Run Code Online (Sandbox Code Playgroud)
这会产生一个 BytesWarning,如下所示:
> python -bb -i
Python 3.8.0
Type "help", "copyright", "credits" or "license" for more information.
>>> v1 = b'foo'
>>> v2 = 'foo'
>>> v1 == v2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
BytesWarning: Comparison between bytes and string
Run Code Online (Sandbox Code Playgroud)