Можете ли вы заставить Python3 выдавать ошибку при сравнении строк с байтами - PullRequest
4 голосов
/ 30 мая 2020

При преобразовании кода из Python 2 в Python 3 одна проблема заключается в том, что поведение при проверке строк и байтов на равенство изменилось. Например:

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

ничего не печатает на Python 3 и «Они совпадают!» на Python 2. В этом случае это легко обнаружить, но во многих случаях проверка выполняется для переменных, которые могли быть определены в другом месте, поэтому нет очевидной информации о типе.

Я хотел бы сделать Python 3 Интерпретатор выдает ошибку всякий раз, когда есть проверка равенства между строкой и байтами, а не молча делает вывод, что они различны. Есть ли способ выполнить sh это?

Ответы [ 2 ]

6 голосов
/ 30 мая 2020

( EDITED : для устранения проблемы, из-за которой я неправильно предполагал, что изменение __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!")

просто выбросит:

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 также не позволяет вам переопределять методы для встроенных типов.

2 голосов
/ 01 июня 2020

Существует опция -b, которую вы можете передать интерпретатору Python, чтобы он выдал предупреждение или ошибку при сравнении byte / str.

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