【问题标题】:Can a conversion to string raise an error? [duplicate]转换为字符串会引发错误吗? [复制]
【发布时间】:2016-08-16 12:23:54
【问题描述】:

我想知道转换为字符串,即str(sth) 是否会引发像float(sth) 这样的异常? 我问这个知道是否有必要将我的代码包装在:

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

确保执行不会因为转换失败而停止。

这在 Python 2 和 3 中是否也有所不同,因为 str 类在它们中有所不同??

【问题讨论】:

  • 代码中执行“某事”的每个部分都可能出错,从而导致错误。 ;-) 但是由于您不能将所有内容都放在try except 中,所以我也会看看出现问题的可能性有多大。如果 canhce 很大,请放入他们自己的 try except 块中。如果机会较低,那么您最好将其放在具有多个代码行的 try except 块中。
  • @Tenzin:这不仅仅是异常发生的可能性的问题,而是出现异常时正确行为的问题。 OP 并没有含糊地问“嘿,有什么问题吗?”;相反,(s)他特别询问字符串转换是否具有“这个值不能转换为字符串”的概念(ValueError),因为如果是这样,(s)他有一个合理的方法来处理他的/她的情况。
  • 高度嵌套的数据结构可能会因为递归限制而触发异常...

标签: python string python-3.x casting


【解决方案1】:

如果您遇到在__str__(或__repr__,如果未定义__str__)中显式引发异常的自定义类。或者,例如一个从__str__返回bytes对象的类:

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

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

但就个人而言,我从未见过这个,我很确定没有人见过;这样做是愚蠢的。同样,__str__ 或边缘情况的实现中的愚蠢错误可能会创建另一个Exception。看看如何将 Python 推向这些边缘情况很有趣(请查看@user2357112 此处的答案)。

除了这种情况,在这种情况下,没有内置函数通常会引发异常,因为它是在 Py2Py3 中为所有内置函数定义的。

对于用户定义的类str,如果在 Python 3 中未定义,则默认使用 object.__str__,在 Python 2 中,如果类是新样式类(继承自 object),则使用它。

如果一个类是旧式类,我相信它是用于类的classobj.__str__ 和用于实例的instance.__str__

一般来说,我不会明白这一点,特殊情况还不够特别。

【讨论】:

  • 类本身是classobj.__str__,实例是instance.__str__
  • @Random832 记录和编辑;感谢您的提示。
【解决方案2】:

理论上可以,但实际上几乎可以肯定不会。 str 函数的工作方式是调用它正在转换为字符串的对象的__str__ 函数。内置类型如List、数字类型和其他类型将返回您所期望的值,[x,y,z] 用于List,数字作为字符串用于数字类型等。object 有一个@987654329 @ 方法提供类似<generator object <genexpr> at 0x7fdb2fa6a640> 的输出,这通常不是很有用但不会引发异常。

因此,在任何内置函数上调用 str 几乎肯定不会引发异常(诚然,我在 Python 文档中找不到对此的保证,但我无法想象会发生这种情况的情况)

也就是说,它是自定义类的possible to override __str__ 方法。如果这样做了,那么该方法可能会引发异常,就像程序员可以编写的任何其他函数一样——故意异常、未捕获的IndexError 或类似的,等等。即使你没有覆盖__str__,如果您使用的模块确实如此,那么该模块的作者完全有可能在一些罕见的边缘犯了一些错误,这会引发异常。

底线:如果每个人都做好了自己的工作,这不应该,但它可以。在几乎任何实际情况下,我都不会费心尝试/捕捉。

【讨论】:

  • 如果内存不足怎么办?这实际上可能发生在长列表中。
  • 说得好!是的,MemoryError 可能会出现在 str 方法期间,以及 KeyboardInterrupt,可能还有一些我忘记了。如果有人合理地预计其中任何一种可能会发生,最好抓住它们 (Though it's sometimes challenging to catch MemoryErrors)
【解决方案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,您可能会遇到 printing 对象产生部分输出并且 然后 引发异常的情况,即使它表面上不应该达到打印任何内容的阶段:

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

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

这是由于过时的tp_print C 级挂钩。

str 使用包含非 ASCII 字符的 unicode 对象时,您还可以获得 Python 2 特定的 UnicodeEncodeError,因为 Python 2 str 对象是字节字符串:

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

【讨论】:

  • 在示例中使用 python2 有什么原因吗?
  • @Chris_Rands:因为我正在考虑添加 Python 2 特定的 str 案例,其中包含非 ASCII 字符的 unicode 对象,我忘记将我的示例与Python 3.x 标签。
【解决方案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())
''
>>> 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-06
    • 2019-10-04
    • 1970-01-01
    • 2021-10-12
    • 2019-07-22
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    相关资源
    最近更新 更多