【问题标题】:Can you make Python3 give an error when comparing strings to bytes在将字符串与字节进行比较时,你能让 Python3 出错吗
【发布时间】:2020-05-30 09:57:43
【问题描述】:

将代码从 Python 2 转换为 Python 3 时,一个问题是测试字符串和字节是否相等时的行为发生了变化。例如:

foo = b'foo'
if foo == 'foo':
    print("They match!")

在 Python 3 上不打印任何内容,并且“它们匹配!”在 Python 2 上。在这种情况下很容易发现,但在许多情况下,检查是针对可能已在其他地方定义的变量执行的,因此没有明显的类型信息。

我想让 Python 3 解释器在字符串和字节之间进行相等测试时给出错误,而不是默默地断定它们不同。有没有办法做到这一点?

【问题讨论】:

  • 请注意1 == "one" 也只给出False,而1 == 1.0 给出True。 Python 不会将比较不同类型的值视为错误,它的语义取决于所涉及的类型。
  • 是的,但至关重要的是,这些示例在 Python 2 和 Python 3 上给出了相同的答案。如果您有类似的比较,从使用 v2 解释器更改为 v3 解释器不应该默默地改变控制代码的流程。对于 byte 与 str 比较,情况并非如此。
  • 我想我希望有一些解释器标志旨在帮助从 2 到 3 的转换,这些标志修改了解释器的行为,大概有一些性能成本,以帮助识别这些潜在的隐藏更新时容易遗漏的问题。

标签: python python-3.x python-2to3


【解决方案1】:

已编辑:修复我错误地建议修改实例上的__eq__ 会影响@user2357112supportsMonica 建议的== 评估的问题)。

通常,您可以通过覆盖您想要保护的类型的 __eq__ 方法来实现这一点。 不幸的是,对于内置类型,尤其是 strbytes,这是无法做到的,因此代码如下:

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!")

只会扔:

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.")

按如下方式使用:

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!")
TypeError: Comparison between `bytes` and `str` detected.

另一种选择是破解您自己的 Python 分支并覆盖 __eq__。 请注意,Pypy 也不允许您覆盖内置类型的方法。

【讨论】:

  • str_eq_bytes 的东西似乎不是按照你的使用方式编写的 - 把它放在 and 中是没有意义的。
  • @user2357112supportsMonica and 应该是 or,感谢您的发现!至于第二条评论,您可以(如果允许的话)在类或实例上覆盖它,不同之处在于您将“保护”所有实例或仅一个特定实例。
  • 大多数魔术方法只有在对象类型上定义时才有效。这部分是为了速度,部分是为了避免出现问题,例如让repr(Dog) 调用Dog.__repr__(这是为了处理Dog instances)。
  • 当我开始修改解释器以添加您建议的代码时,我发现 bytearrayobject 中已经有代码可以检测和警告字节/字符串测试,这导致我选择了我在我的答案。如果没有您的建议,我不会找到它,谢谢。
【解决方案2】:

有一个选项,-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)

这会产生一个 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

【讨论】:

    猜你喜欢
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多