Python3, когда UserString не ведет себя как строка? - PullRequest
0 голосов
/ 15 января 2020

В Python3 Я использую UserString для расширения функциональности встроенных строк. Обычно UserString s ведут себя так же, как str s, но с re я сталкиваюсь с неожиданным TypeError:

bpython version 0.17.1 on top of Python 3.6.9 /usr/bin/python3

import re
from collections import UserString

s = UserString('foo')
re_repetitions = re.compile(r"(/)\1{1,}", re.DOTALL)
re_repetitions.sub(r"\1", s)

Traceback (most recent call last):
  File "<input>", line 1, in <module>
    re_repetitions.sub(r"\1", s)
TypeError: expected string or bytes-like object

- почему это так? Обычно UserString "крякает" как строка, но re не рассматривает это как таковое? Где еще UserString не ведет себя как str?

Ответы [ 2 ]

2 голосов
/ 15 января 2020

Экземпляр UserString не является экземпляром str, но содержит a str:

re_repetitions.sub(r"\1", s.data)
0 голосов
/ 23 января 2020

Я хотел бы добавить некоторую информацию о классе UserString.

Python встроенные типы, такие как str, на самом деле не являются реальными Python классами, но C конструкции (при условии стандартной реализации Python, CPython). Это помогает с быстротой и, вероятно, с совместимостью Python - C, но поведение встроенных модулей может отличаться от обычного пользовательского класса. Существуют случаи, когда эта деталь реализации имеет значение.

Это пример такой ситуации. Возможно, механизм регулярных выражений re написан на C и работает с C строками. UserString "имитирует строковый объект" , но это не один.

Кажется, что все подпрограммы C не работают с UserString. Например, вы не можете запустить importlib, subprocess или os.path для этого класса. В 2001 году было предложение по улучшению . Но исправление не было реализовано, потому что не существует простого способа сделать это.

Следовательно, стандартного способа его исправить не существует. Вам нужно использовать какой-то обходной путь: либо .data, как в ответе Чепнера, либо как в связанном вопросе, сделайте str(UserString('foo')).

Кроме того, сообщение об ошибке

TypeError: expected string or bytes-like object

на самом деле означает, что ему нужен str объект. По умолчанию «строка» означает str в Python. Что может сбивать с толку в случае «строковых» объектов и т. Д. c.


Наконец, в моем реальном случае использования мне пришлось использовать строковый класс MyString, который можно расширить с новыми методами в будущем. В настоящее время я просто использовал MyString = str и думал, что он будет легко расширяться в будущем, когда возникнет необходимость.

Необходимость пришла, я определил class MyString(UserString), и мои тесты сказали мне, что им нужно строка. Теперь, немного неловко и не Pythoni c, половина моего кода обрабатывает MyString как строку, а другая половина - MyString('foo').data. И что еще хуже, этот класс MyString является частью интерфейса одного из модулей. Таким образом, пользователь должен знать подробности реализации интерфейса модуля ...

В моем случае кажется, что я могу кодировать эту проблему. Но это требует некоторого переписывания всего модуля. Так что, вероятно, функция, реализованная в UserString, не стоит усилий прямо сейчас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...