3

让我首先说:这是用于深奥目的 - 不是生产代码。我正在用一行 Python 代码做一些事情,因此我需要表达式而不是语句。(编辑:我正在将代码机械编译成单行(主要是)等效的 Python 代码,BitBucket - onelinepython。请注意,它正在进行中,因此我在最初提到它时保持沉默)

我基本上想做两件事:

  • 调用一个引发我选择的异常实例的函数,例如:

    raise_exception(WhateverException())

  • 在封闭的环境中运行一个函数,我可以在其中获取引发的异常实例,如果引发了异常实例,否则返回被调用函数的返回值。例如:

    has_exception, return_or_exception = check_exception(f, param1, param2, ...)

理想情况下,我想用一些默认库或内置函数来做到这一点(不管我有多少要混蛋它的预期用途)。我不需要与我提供的示例具有完全相同签名的函数,只是我可以将其分解成足够接近的东西。不过,我确实有一个限制:不使用 eval() 或等效函数

编辑:我知道我可以定义自己的函数来执行此操作,但是他们仍然必须遵循它们是单个表达式的限制。因此,在函数定义中使用raise和内部的解决方案已被淘汰。try不幸的是,函数定义、raise-statement 和 try-blocks 是语句而不是表达式。

至于我尝试过的任何解决方案。答案还没有。我最接近如何解决这个问题的想法是滥用unittest断言功能,但我认为这是一个死胡同。

编辑 2:为了清楚起见,我可以使用在其代码中某处使用raise-statements 或try-blocks 的模块或其他模块。我的目标是获取一些代码并将其转换为等效的单行代码(包括我可能正在使用的任何辅助函数)。但由于我希望它在默认安装的 Python 上工作,我只想使用默认库。

4

4 回答 4

2

To raise an exception:

>>> import warnings
>>> WV = type("WV", (Warning, ValueError), {})
>>> warnings.simplefilter("error", WV)
>>> warnings.warn("wv", WV)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.WV: wv

To catch an exception:

>>> import unittest
>>> res = type("TR", (unittest.TestResult, ), dict(addError=lambda self, test, err: setattr(self, '_last_err', err)))()
>>> unittest.FunctionTestCase(lambda: [][0])(res)
>>> res._last_err
(<type 'exceptions.IndexError'>, IndexError('list index out of range',), <traceback object at 0x2b4358e69950>)

Note that the warnings method will only work for exceptions that derive from Warning, but you should always be able to multiply-inherit; here's an example:

>>> WS = type("WS", (Warning, StopIteration), {})
>>> warnings.simplefilter("error", WS)
>>> list(type("R", (object,), dict(__init__=lambda self, stop: (setattr(self, 'stop', stop), setattr(self, 'i', 0), None)[-1], __iter__=lambda self: self, next=lambda self: (self.i, setattr(self, 'i', self.i + 1))[0] if self.i < self.stop else warnings.warn("Stop", WS)))(5))
[0, 1, 2, 3, 4]
于 2012-06-19T10:08:24.797 回答
1

您可以定义自己的函数来执行此操作:

def raise_exception(ex):
    raise ex

def check_exception(f, *args, **kwargs):
    try:
        return False, f(*args, **kwargs)
    except Exception as e:
        return True, e
于 2012-06-18T19:41:39.047 回答
1

这个答案表明通常不可能用表达式捕获异常。我也很确定不使用raise. (您可以使用1/0or之类的表达式生成一些特定的异常dict['keyThatWillNeverExist'],但不能使用任意异常信息生成任意异常。)

The language reference says:

The Python interpreter raises an exception when it detects a run-time error (such as division by zero). A Python program can also explicitly raise an exception with the raise statement. Exception handlers are specified with the try ... except statement.

Although this doesn't rule out the possibility that some dark corner of the language specification allows raising exceptions in other ways, the statement is pretty straightforward: you raise exceptions with raise and catch them with try/except.

Note that using unittest, or any other Python library, is unlikely to be a real solution in your sense, because unittest contains functions written in Python that use try/except. So if you're okay with using unittest, you ought to be okay with writing your own functions.

I imagine it might be possible to achieve your goal by "cheating" and writing a C extension that provides functions doing what you want. But that's not really converting it to equivalent Python code.

于 2012-06-18T20:05:28.177 回答
-1

You are asking how to raise an exception without using raise and catch an exception without using except. Your reluctance to use these statements is because you can't use more than one statement in a single line of code, and you have the idea to compile Python modules into oneliners.

Short answer: Well, you can't.

And even if you could, why would you? It's a completely meaningless effort. The code is not faster or even significantly smaller because it is in one line. It goes against the idea of Python as well. And if you want to obfuscate it, there are much better ways, including compiling it to bytecode.

Longer answer:

You could implement your own exception system, independent of the Python exceptions, but that would be astonishingly slow, and this would still not catch the Python exceptions, so it's not useful in your case.

For the raise-statement, you could re-implementing the raise statement as a function in C, but this you seem to think is cheating, and I also don't see how it would be possible with other statements, such as except.

You could also move out some statements into functions in a separate module, but this is of course then no longer actually a one-liner module in any meaningful way, and not all statements are easily wrapped like this, except being the most relevant case here. You'd have to wrap the whole try/except block, but the resulting function would in turn also only take expressions as parameters, so you would have to extract the blocks into functions, and you'd end up needing to basically re-implement most of Python as a statement-less language, which is silly. And you'd end up with the helper functions in a separate module, which you don't want to.

So the answer to your question of how to raise an exception without using raise and catch an exception without using except is "You don't".

于 2012-06-19T09:22:54.147 回答