Подтвердить что ты не робот

Unicode_literals и type()

У меня возникают проблемы с поддержкой python2 и python3 при вызове type(). Это демонстрирует проблему:

from __future__ import unicode_literals

name='FooClass'
type(name, (dict,), {})

Нет проблем на python3, но на python2:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    type(name, (dict,), {})
TypeError: type() argument 1 must be string, not unicode

Это связано с Любые ошибки с использованием unicode_literals в Python 2.6?. В этом вопросе кто-то рекомендует typecasting для байта, так что наивно я думал об использовании six.b():

A "поддельный" байтовый литерал. данные всегда должны быть нормальным строковым литералом. В Python 2, b() возвращает 8-битную строку. В Python 3 данные кодируются с кодировкой latin-1 в байтах.

Итак, это выглядит так:

from __future__ import unicode_literals
import six

name='FooClass'
type(six.b(name), (dict,), {})

Но он не работает как на python2, так и на python3:

$ python2 test.py 
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    type(six.b(name), (dict,), {})
TypeError: type() argument 1 must be string, not unicode

$ python3 test.py 
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    type(six.b(name), (dict,), {})
TypeError: type() argument 1 must be str, not bytes

Итак, кажется, что действительно, type() хочет, чтобы python2 str была python3 bytestring на python2, но ему нужна строка python3, которая представляет собой строку юникода python2 на python3.

Как вы думаете?

Я что-то не понимаю?

Или существует ли реальная несовместимость с type() на python 2 и 3?

Нет ли способа иметь один и тот же вызов type(), поддерживающий как 2, так и 3?

Не должен ли инструмент, подобный six, обернуть вокруг type() в этом случае?

4b9b3361

Ответ 1

six.b записывается в предположении, что вы не будете использовать unicode_literals (и что вы передадите ему строковый литерал, как указано в документации), поэтому реализация Python 2 просто def b(s): return s как строковый литерал Python 2 уже является байтовой строкой.

Либо не используйте unicode_literals в этом модуле, либо используйте (как следует из комментариев) str(name). В Python 3 это не-op. В Python 2 он бесшумно преобразует строку юникода в байтовую строку (предполагая некоторую кодировку, которую я не могу запомнить, но это надмножество ASCII, поэтому все должно быть хорошо).