Ответ 1
Нашел вашу проблему:
Когда передано кодирование, codecs.open
возвращает StreamReaderWriter
, который на самом деле является только оболочкой (не подклассом, это "состоящий из" отношения, а не наследования) StreamReader
и StreamWriter
. Проблема в том, что:
-
StreamReaderWriter
предоставляет "обычный"read
метод (то есть он принимает параметрsize
и что он) - Он делегирует внутренний метод
StreamReader.read
, где аргументsize
- это всего лишь подсказка относительно количества прочитанных байтов, но не предел; второй аргументchars
является строгим ограничителем, ноStreamReaderWriter
никогда не передает этот аргумент (он его не принимает) - Если
size
намечено, но не ограничено использованиемchars
, еслиStreamReader
имеет буферизованные данные, и он достаточно большой, чтобы соответствовать подсказкеsize
StreamReader.read
, слепо возвращает содержимое буфера, а не ограничивает это в любом случае основано на подсказкеsize
(в конце концов, толькоchars
накладывает максимальный размер возврата)
API StreamReader.read
и значение size
/chars
для API - это единственная зарегистрированная вещь; тот факт, что codecs.open
возвращает StreamReaderWriter
не является договорным, а также тот факт, что StreamReaderWriter
wraps StreamReader
, я просто использовал ipython
??
magic для чтения исходного кода модуля codecs
для проверки это поведение. Но документально или нет, что он делает (не стесняйтесь читать исходный код для StreamReaderWriter
, все это на уровне Python, так что это легко).
Лучшим решением является переход на io.open
, который быстрее и правильнее в каждом стандартном случае (codecs.open
поддерживает кодеки weirdo, которые не конвертируются между bytes
[Py2 str
] и str
[Py2 unicode
], а, дескриптор str
в str
или bytes
в bytes
кодировки, но это невероятно ограниченный случай использования; большую часть времени вы конвертируете между bytes
и str
). Все, что вам нужно сделать, это импортировать io
вместо codecs
и изменить строку codecs.open
на:
f = io.open("test.py", encoding="utf-8")
Остальная часть вашего кода может оставаться неизменной (и, скорее всего, будет работать быстрее для загрузки).
В качестве альтернативы вы можете явно обходить StreamReaderWriter
, чтобы получить метод StreamReader
read
и передать предельный аргумент напрямую, например. изменить:
c = f.read(1)
в
# Pass second, character limiting argument after size hint
c = f.reader.read(6, 1) # 6 is sort of arbitrary; should ensure a full char read in one go
Я подозреваю Ошибка Python # 8260, которая охватывает перемежающиеся readline
и read
на codecs.open
созданные объекты файлов, применяется здесь, официально, оно "исправлено", но если вы прочтете комментарии, исправление не было полным (и может быть невозможно завершить данный документированный API); произвольно странные комбинации read
и readline
смогут сломать его.
Опять же, просто используйте io.open
; если вы на Python 2.6 или выше, он доступен, и он просто лучше.