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

Должен ли я избегать преобразования в строку, если значение уже является строкой?

Иногда вам нужно использовать понимание списка, чтобы преобразовать все в строку, включая сами строки.

b = [str(a) for a in l]

Но мне нужно делать:

b = [a if type(a)==str else str(a) for a in l]

Мне было интересно, если str в строке оптимизировано достаточно, чтобы не создавать другую копию строки.

Я пробовал:

>>> x="aaaaaa"
>>> str(x) is x
True

но это может быть связано с тем, что Python может кэшировать строки и повторно использовать их. Но является ли это поведение гарантированным для любого значения строки?

4b9b3361

Ответ 1

Тестирование, если объект уже является строкой, медленнее, чем просто преобразование в строку.

Это потому, что метод str() также делает тот же самый тест (это объект уже строка). Вы a) выполняете двойную работу, и b) ваш тест медленнее загружается.

Примечание: для Python 2 с помощью str() on unicode объекты включают неявный код в ASCII, и это может завершиться неудачей. Возможно, вам все равно придется заниматься специальными делами таких объектов. В Python 3 нет необходимости беспокоиться об этом краевом случае.

Как есть некоторые обсуждения вокруг этого:

  • isinstance(s, str) имеет другое значение, когда s может быть подклассом str. Поскольку подклассы обрабатываются точно так же, как и любой другой тип объекта с помощью str() (на объект вызывается либо __str__, либо __repr__), это различие имеет значение здесь.
  • Вы должны использовать type(s) is str для точных проверок типов. Типы - это синглтоны, воспользуйтесь этим, is быстрее:

    >>> import timeit
    >>> timeit.timeit("type(s) is str", "s = ''")
    0.10074466899823165
    >>> timeit.timeit("type(s) == str", "s = ''")
    0.1110201120027341
    
  • Использование s if type(s) is str else str(s) значительно медленнее для случая, отличного от строки:

    >>> import timeit
    >>> timeit.timeit("str(s)", "s = None")
    0.1823573520014179
    >>> timeit.timeit("s if type(s) is str else str(s)", "s = None")
    0.29589492800005246
    >>> timeit.timeit("str(s)", "s = ''")
    0.11716728399915155
    >>> timeit.timeit("s if type(s) is str else str(s)", "s = ''")
    0.12032335300318664
    

    (Тайминги для случаев s = '' очень близки и сохраняют места обмена).

Все тайминги в этом сообщении были проведены на Python 3.6.0 на Macbook Pro 15 "(середина 2015 года), OS X 10.12.3.