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

Может ли преобразование в строку вызвать ошибку?

Мне было интересно, может ли преобразование в строку i.e. str(sth) вызвать исключение, например, например, float(sth)? Я прошу об этом знать, нужно ли вставлять мой код в:

try:
    x = str(value)
except ValueError:
    x = None

чтобы убедиться, что выполнение не прекращается из-за отказа преобразования.

Также отличается ли это от Python 2 и 3, так как класс str отличается от них?

4b9b3361

Ответ 1

Если вы столкнулись с пользовательским классом, который явно вызывает исключение в __str__ (или __repr__, если __str__ не определен). Или, например, класс, который возвращает объект bytes из __str__:

class Foo:
    def __str__(self):
        return b''

str(Foo()) # TypeError: __str__ returned non-string (type bytes)

Но лично я никогда этого не видел, и я уверен, что никто не имеет; было бы глупо это делать. Точно так же глупая ошибка при реализации __str__ или краевых случаев может создать еще один Exception. Интересно посмотреть, как вы могли бы подталкивать Python к этим крайним случаям (смотрите @user2357112 здесь).

Кроме этого, никакие встроенные функции вообще не генерируют исключение в этом случае, поскольку он определен для всех из них в Py2 и Py3.

Для пользовательских классов str будет использовать object.__str__ по умолчанию, если он не определен в Python 3, а в Python 2 использовать его, если класс является новым классом стиля (наследуется от object).

Если класс является старым классом стиля, я считаю, что для экземпляров используется classobj.__str__ для классов и instance.__str__.

В общем, я бы этого не заметил, для этого особых случаев недостаточно.

Ответ 2

В теории да, это возможно, но на практике это почти наверняка не будет. Способ работы str - это вызов функции __str__ объекта, который он преобразует в строку. Встроенные типы типа List, числовые типы и другие будут возвращать значения о том, что вы ожидаете, [x,y,z] для List, число как строка для числового типа и т.д. object имеет __str__, который дает результат типа <generator object <genexpr> at 0x7fdb2fa6a640>, который часто не очень полезен, но не вызывает исключения.

Таким образом, вызов str для любого встроенного устройства почти наверняка не приведет к возникновению исключения (по общему признанию, я не могу найти гарантии для этого в документации на Python, но я не могу представить ситуацию, в которой это произойдет )

Тем не менее, можно переопределить метод __str__ для настраиваемого класса. Если это будет сделано, то этот метод может вызвать исключение, как и любая другая функция, которую программист мог бы написать, - это преднамеренное исключение, неотображаемое IndexError или тому подобное и т.д. Даже если вы не переопределяете __str__, если вы используете модуль, который делает это, вполне возможно, что автор этого модуля допустил некоторую ошибку на каком-то редком крае, которое вызовет исключение.

Нижняя строка: Это не должно, если все выполняли свою работу правильно, но это могло бы быть. Почти в любой практической ситуации я бы не стал пытаться поймать.

Ответ 3

Легко. У вас может быть класс контейнера с рекурсивно-небезопасным __str__ или __repr__, который заканчивается опорным циклом:

import numpy

x = numpy.empty([1], dtype=object)
x[0] = x
str(x)  # RuntimeError: maximum recursion depth exceeded

Или просто очень сильно вложенный объект:

x = []
for i in xrange(2000):
    x = [x]

str(x)  # RuntimeError: maximum recursion depth exceeded while getting the repr of a list

Если даже с помощью встроенных типов вы можете получить что-то намного хуже, чем исключение:

x = {}
for i in range(1000000):
    x = {1: x}
str(x)  # python.exe has stopped working
        # Windows can check online for a solution to the problem.

Это переполнение стека C, поскольку dict_repr не использует (в настоящее время) Py_EnterRecursiveCall. Вы не можете поймать это с помощью блока except!

Возвращаясь к более мирским ошибкам, вы можете иметь weakref.proxy для мертвого объекта:

import weakref

class Foo(object):
    pass

str(weakref.proxy(Foo()))  # ReferenceError: weakly-referenced object no longer exists

Или вы могли бы просто написать класс, который поднимает все, что вам нужно, в __str__ или __repr__:

class Foo(object):
    def __str__(self):
        raise Exception

str(Foo())  # Raises an Exception

Конкретно для Python 2 вы можете получить случай, когда print объект создает частичный вывод, а затем вызывает исключение, хотя он якобы никогда не должен был доходить до стадии печати:

class Foo(object):
    def __repr__(self):
        raise Exception

print [Foo()]  # Prints a single opening bracket, then raises an Exception!

Это связано с устаревшим tp_print крюком уровня C.

Вы также можете получить Python 2-специфичный UnicodeEncodeError, когда str -ing a unicode объект, который содержит символы, отличные от ASCII, поскольку объекты Python 2 str являются байтами:

str(u'\u1000')  # Fails on Python 2 only

Ответ 4

Чтобы добавить к другим ответам, str() не генерирует исключение во многих (возможно, неожиданных) контекстах, например, вы можете применить его к функции, генератору или самому себе. Однако я не могу представить ситуацию, в которой вы действительно хотели бы сделать это на практике.

>>> def a(): pass
... 
>>> str(a)
'<function a at 0x7fc43614e048>'
>>> 
>>> str(x for x in range(3))
'<generator object <genexpr> at 0x7fc434b95f10>'
>>> 
>>> str(str())
''
>>>