Python 无法将非运算符绑定到一元操作数
在Python中,如果“不”操作员遵循一个位操作员(例如'&'或'|'),则结果是语法错误。当然,这将是二进制值的位操作,但这应该是可以的。就我记得而言,C中没有问题。
例如,这起作用:
a = 0
b = 1
anot = not(a)
bnot = not(b)
c = anot | bnot
但这是失败的:
c = not(a) | not(b)
这些工作:
c = not(a) | (not(b))
c = not a | (not b)
有人可以让我见解为什么要这么做吗?不寻找解决方法,只是对实施的解释。同时,我将努力了解源代码和CFG,以查看是否可以了解更多信息。到目前为止,我还没有在堆栈或其他Google上找到任何类似的问题。谢谢!
In Python, if a 'not' operator follows a bitwise operator (such as '&' or '|') the result is a syntax error. Granted that it will be a bitwise operation on a binary value, but that should be OK. There is no issue in C as far as I recall.
For example, this works:
a = 0
b = 1
anot = not(a)
bnot = not(b)
c = anot | bnot
but this fails:
c = not(a) | not(b)
these work:
c = not(a) | (not(b))
c = not a | (not b)
Can anyone give me insight as to why this should be? Not looking for workarounds, just an explanation of the implementation. In the meantime, I will struggle through the source code and CFGs to see if I can learn more. So far, I have not found any similar question on the Stacks or other Googles. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请记住,
not
是关键字,而不是函数。因此表达式not(a)
在语义上等同于not a
。前两个示例中的括号对绑定运算符没有任何帮助。但第三个示例中的(not a)
将强制首先对内部表达式求值。Remember that
not
is a keyword, not a function. So the expressionnot(a)
is semantically equivalent tonot a
. The parens in your first two examples do nothing to help bind the operator. But the(not a)
in the third example will force the evaluation of the inner expression to happen first.Python语法确实清楚地表明了正在发生的事情:(我编辑了不同比较运算符的长列表,除非非终端名称和操作员本身,
而不是必须是
的操作数代码>不表达式不能是比较
,或者是比较
的优先链中的东西。并且|
的操作数必须为bitwise_or
(bitwise_xor
右侧),或者是这些优先链的东西。由于bitwise_or
比不是
更远的链条,因此abitwise_or
表达式可以是不是
而不是|
的操作数中的任何一个。所以
不是0 | 1
表示不是(0 | 1)
,因为0 | 1
可以是不是
的操作数,而不是0
不能是|
的操作数。和0 |不是1
是语法错误,因为不是1
不能是|
的操作数,并且没有其他方法来解析表达式。请注意,这是不是与C相同的C。在C中,所有Unary前缀操作员比任何二进制操作员都更紧密地绑定,因此
!0 | 1
表示>
(!0)| 1
,是1。这与python表达式而不是0 |相反。 1
,是false
。当然,这不是为什么 python语法的解释,而我并不能完全对推理进行全面的历史性描述。显然,认为意思是
不是(a< b)
而不是(不是a)< B
。后者的解释很少是必需的,因此它具有一定的意义。同样,这与其他布尔运营商的工作方式一致。a< B和B< C
实际上意味着幼稚的读者可能会期望什么。在C中也是如此:a< B&& B< C
不需要括号来提供预期的解析。 (但是请注意,在C,&
和|
中,与Python的运营商的优先列表中不在同一位置。)因此,这都是可以理解的,但是问题是为什么写语法以禁止像
1 |这样的明确表达。不是
,它只能以一种方式解析,无论其优先级如何。在这里,我只能猜测。当然,可以编写语法,该语法允许这样的明确的表达方式。但是,这并不容易,如果您将自己限制在简单的BNF上(甚至现在在Python语法中使用的扩展BNF变体)。问题是级联优先样式不允许循环。如果先例没有形成一致的部分订单,则解析器报告歧义。另一方面,如果您使用类似YACC/野牛的解析器,或通过搜索该短语找到的许多操作员解析技术中的任何一个,那么这一点都不困难。因此,在没有基于优先权的歧义的情况下使用解析器生成器的决定可能与实施有关。
您遇到的歧义性的含糊不清是一项单位运算符的含义,当人们试图编写包括
let
表达式的语言的语法时,人们通常会遇到这种歧义:“ let”< var> “ =”< expr> “在”< expr>
中。在该构造中,第二个< expr>
是贪婪的:它可以扩展到可以扩展。但是,没有明显的原因让
表达式本身在操作员的右侧不应合法:LET
表达式评估为29/6(6-(1/6))
,因此有充分的理由相信z
将为14.5,而不是报告语法错误的解析器。但是,使用天真编写的语法,您要么获得语法错误或一些奇怪的歧义报告。当语法实现时,您会得到语法错误,就像python实现不是
的方式相同,并且出于相同的原因:let
表达式无法在任一侧成为*
的操作数。如果您尝试修改级联优先语法以允许在
**
的右侧允许let
,则通常会出现新的歧义。当解析器到达-
时,它可以选择终止乘法(3 *令x = 6 in x)-1/6
或让令
吸收表达式的其余部分,3 *(令x = 6 in x -1/6中)
。我不认为大多数人类读者会期望第一次解析,尽管您永远不知道,但是解析器并不能以人类的直觉运作。 (这通常是一件好事。)对于操作员预言解析器来说,这是微不足道的,因为您要做的就是定义
LET
,左侧最高优先级,右侧最低优先级。令
操作员本身一直在解析器堆栈上,直到解析器被迫将其弹出为止,因为它到达了表达式或近亲括号的末端,从而有效地“隐藏”*操作员。因此,一切都按预期工作。
The Python grammar does clearly indicate what's going on: (I edited out the long list of different comparison operators, which are all the same except for the non-terminal name and the operator itself)
So, the operand for
not
must be acomparison
, or something down the precedence chain fromcomparison
. And the operands for|
must bebitwise_or
(bitwise_xor
on the right) or something down the precedence chain for those. Sincebitwise_or
is further down the chain thannot
, abitwise_or
expression can be the operand ofnot
but anot
expression cannot be either of the operands of|
.So
not 0 | 1
meansnot (0 | 1)
, because0 | 1
can be the operand ofnot
whilenot 0
cannot be an operand of|
. And0 | not 1
is a syntax error becausenot 1
cannot be an operand of|
and there's no other way of parsing the expression.Note that this is not the same as C. In C, all of the unary prefix operators bind more tightly than any binary operator, so
!0|1
means(!0) | 1
, which is 1. That's opposite to the Python expressionnot 0 | 1
, which isFalse
.Of course, that's not an explanation for why the Python grammar is written that way, and I'm not in a position to give a complete historic account of the reasoning. Apparently, it was considered desirable that
mean
not (a < b)
, rather than(not a) < b
. The latter interpretation would very rarely be desired, so it makes a certain amount of sense. Also, that's consistent with how the other boolean operators work;a < b and b < c
does in fact mean what a naïve reader would probably expect. And that's true in C, as well:a < b && b < c
doesn't need to be parenthesised to provide the intended parse. (But note that in C,&
and|
are not in the same place in the precedence list as Python's operators with the same names.)So that's all somewhat understandable, but the question is why the grammar is written so as to prohibit unambiguous expressions like
1 | not a
, which can only be parsed in one way regardless of precedence. Here, I can only guess.Certainly, it is possible to write a grammar which allows unambiguous expressions like that. But it's not easy, if you're limiting yourself to simple BNF (or even the extended BNF variant now used in the Python grammar). The problem is that the cascading precedence style doesn't allow loops; if precedences don't form a consistent partial order, the parser reports ambiguities. On the other hand, if you use a Yacc/Bison-like parser generator, or any of the many operator-precedence parsing techniques you'll find by searching for that phrase, then it's not difficult at all. So the decision to use a parser generator without precedence-based disambiguation is probably related to the implementation.
The kind of ambiguity you run into with lower precedence unary operators is the following, which people usually run into when they try to write a grammar for languages which include
let
expressions:"let" <var> "=" <expr> "in" <expr>
. In that construct, the second<expr>
is greedy: it extends as far as it can be extended. But there's no obvious reason why thelet
expression itself shouldn't be legal on the right-hand side of an operator:The
let
expression evaluates to 29/6(6 - (1 / 6))
, so there's every reason to believe thatz
will be 14.5, rather than the parser reporting a syntax error. With a naively-written grammar, though, you either get the syntax error or some odd ambiguity report. You get the syntax error when the grammar implementslet
in the same way that Python implementsnot
, and for the same reason: thelet
expression cannot be the operand of*
, on either side.If you try to modify the cascading precedence grammar to allow
let
on the right-hand side of*
, you typically end up with a new ambiguity; when the parser reaches the-
, it has the choice of terminating the multiplication( 3 * let x = 6 in x) - 1/6
or letting thelet
absorb the rest of the expression,3 * (let x = 6 in x - 1/6)
. I don't think most human readers would expect the first parse, although you never know, but a parser doesn't operate with human intuitions. (That's usually a good thing.)This is trivial with an operator-precedence parser, because all you need to do is to define
let
with highest precedence on the left and lowest precedence on the right. Thelet
operator itself stays on the parser stack until the parser is forced to pop it off, because it reaches the end of the expression or a close parenthesis, which effectively "hides" the precedence of the*
operator. Thus, everything works as expected.