python-3.x - 在列表理解中引发异常:语法无效
问题描述
为了检查一个方法是否被正确调用,我想检查每个字符,使程序员不可能错误地使用该方法。因为该方法将在 Web 服务器中调用return redirect(...)
,而不是返回错误值(如False
or None
),所以我想引发异常。
def redirect(uri):
[raise ValueError('URI must be URL-encoded, ASCII only!') for c in uri if not (32 <= ord(c) <= 127)]
这给出了“无效语法”异常:
File "server.py", line 115
[raise ValueError('URI must be URL-encoded, ASCII only!') for c in uri if not (32 <= ord(c) <= 127)]
^
SyntaxError: invalid syntax
我可以通过各种方式解决这个问题,但我想知道:为什么不允许在列表理解中提出?
解决方案
句法
从语法的角度来看,您的答案在完整的语法规范中。
raise
终端仅出现在从stmt
(语句)派生的规则中:
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (... | flow_stmt | ...)
flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
raise_stmt: 'raise' [test ['from' test]]
而列表推导的第一部分是test
(布尔值或表达式)或star_expr
( *expr
):
atom: ... | '[' [testlist_comp] ']' | ...
testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
关键是无法从(test|star_expr)
(列表理解的左侧部分)导出语句。因此,您的表达在语法上是错误的。
语义
正如@Neb 在评论中指出的那样,试图返回a的列表理解raise
是没有意义的。
你可能还记得那print
是 Python 2 中的一个语句,在 Python 3 中变成了一个函数:
蟒蛇2:
>>> [print(1) for _ in range(1)]
File "<stdin>", line 1
[print(1) for _ in range(1)]
^
SyntaxError: invalid syntax
蟒蛇 3:
>>> [print(1) for _ in range(1)]
1
[None]
列表理解现在在语法上是正确的。同样,没有语法规则阻止您编写以下代码:
>>> def raiser(): raise ValueError('URI must be URL-encoded, ASCII only!')
...
>>> def redirect(uri): [raiser() for c in uri if not (32 <= ord(c) <= 127)]
...
>>> redirect("abc")
>>> redirect("éàç")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in redirect
File "<stdin>", line 1, in <listcomp>
File "<stdin>", line 1, in raiser
ValueError: URI must be URL-encoded, ASCII only!
但是语义仍然不清楚:您是要执行一个动作(即使用函数的副作用)还是构建一个列表?请记住,列表推导是对函数式语言的借用,我认为尤其是 Haskell。因此,他们不是在这里执行操作。
我引用@Mark Ransom 评论来回答“使用列表推导来解决副作用是 Pythonic 吗? ”问题:
我会更进一步,并指出列表理解中的副作用是不寻常的、出乎意料的,因此是邪恶的,即使您在完成后使用结果列表也是如此。– 马克赎金
我使用这个经验法则:避免列表推导中的任何副作用,即使您使用结果。
推荐阅读
- doctrine-orm - 如何使用 Doctrine 2 DQL ON 覆盖默认的 JOIN 条件
- php - Woocommerce 设置客户提供的注释也返回 html 标签
- c# - 如何将 Excel 表格数据迭代到 DataGridView?
- c# - 使用依赖于记录器的选项验证器创建依赖于选项的自定义记录器时出现循环依赖异常
- c# - 有没有办法缩短重复数学
- php - 我正在使用 PHPExcel 将颜色混合到 excels 单元中,将颜色变化反映到开放式办公室,但不反映到 microsoft-office o
- html - 通过 bulma 文件上传重用来自 fileInput 的闪亮进度条
- javascript - 从模板中的父组件触发子函数
- r - 在 R 中合并 SpatialPoints 和 SpatialPolygons 数据框
- angular - Angular 10:如何在延迟加载的功能模块中重置 RouterConfig