是否有任何方法可以捕获太多的值来解压缩"错误?

时间:2015-08-31 18:07:03

标签: python

我的元组子类的用法:

class MyTuple(tuple):
    def __new__(cls, columns=()):
        return tuple.__new__(cls, tuple(columns))

a, b = MyTuple(columns=('hello', 'world', 42))

给出以下例外:

Traceback (most recent call last):
  File "<stdin>", line 6, in <module>
ValueError: too many values to unpack

ValueError可能有很多原因,所以我需要使用以下内容来捕捉它吗?

try:
    a, b = MyTuple(columns=('hello', 'world', 42))
except ValueError as e:
    if not str(e).endswith('unpack'):
        raise  # false alarm
    # handle unpacking error here..

这似乎相当不优雅..有没有办法可以覆盖元组拆包引发的异常?

更新:实际用例如下

>>> dice = FactSet()
>>> for i in range(1, 7):
...     dice.add('dice', n=i)
...
>>> print dice.n + dice.n == 10   # give me all combinations that add up to 10
XPROD((dice(n=4), dice(n=6))
      (dice(n=5), dice(n=5))
      (dice(n=6), dice(n=4)))
>>> a, b = dice.n + dice.n == 10  # same as above, but unpack the individual die
>>> a
FactSet([
    dice(n=4),
    dice(n=5),
    dice(n=6),
])
>>> b
FactSet([
    dice(n=6),
    dice(n=5),
    dice(n=4),
])
>>> a, b = dice.n + dice.n == 13  # no result should probably raise a more specific exception?
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 0 values to unpack
>>> ab = dice.n + dice.n == 13  # this is much more awkward and forces you to deal with the error in-situ (which might not be what you wanted)
>>> if ab:
>>>     a, b = ab

2 个答案:

答案 0 :(得分:6)

而不是:

a, b = <expression>

执行:

value = <expression>
try:
    a, b = value
except ValueError:
    ...

这是解决此类问题的一般方法:当您的陈述可能由于某种原因而引发相同类型的异常时,只需将该陈述分成多个部分,即可隔离&#34; critical&#34;部分来自其余的代码。

  

有没有办法可以覆盖元组解包引发的异常?

没有。 tuple对象不会引发异常,它由Python解释器引发。执行:a, b, ..., z = something时,解释器在幕后执行以下代码:

it = iter(something)

try:
    a = next(it)
    b = next(it)
    ...
    z = next(it)
except StopIteration:
    raise ValueError('need more than X values to unpack')

try:
    next(it)
except StopIteration:
    pass
else:
    raise ValueError('too many values to unpack (expected Y)')

正如您所看到的,元组(或一般情况下的可迭代)仅被迭代。它不知道发生了什么。

正如您通过阅读CPython's source code所看到的那样,这些例外情况是硬编码的,并且不能被覆盖&#34;。

答案 1 :(得分:1)

根据@ AndreaCorbellini的回答,这是一个自定义迭代器实现,具有合理/可调整的语义:

import collections


class MyTupleIter(collections.Iterator):
    def __init__(self, mt, length):
        self.mt = mt
        self.pos = -1
        self.length = length

    def next(self):
        self.pos += 1
        if self.pos < self.length:
            if self.pos >= len(self.mt):
                return 'empty-value'
            return self.mt[self.pos]
        raise StopIteration


class MyTuple(tuple):
    def __new__(cls, columns=()):
        return tuple.__new__(cls, tuple(columns))

    def __iter__(self):
        return MyTupleIter(self, length=2)


a, b = MyTuple()
print a, b    # empty-value empty-value

a, b = MyTuple(columns=(1,2,3))
print a, b    # 1 2