Python 3.2语法规范 - 函数调用

时间:2012-04-03 04:19:33

标签: python compiler-construction grammar

这是参考Python 3.2。相关语法规则如下(http://docs.python.org/py3k/reference/grammar.html):

power: atom trailer* ['**' factor]
atom: ('(' [yield_expr|testlist_comp] ')' |
       '[' [testlist_comp] ']' |
       '{' [dictorsetmaker] '}' |
       NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME

根据这个,基本的函数调用可能看起来像:

atom '(' ')'

但我相信我们不能只将任何 atom放在那里。例如,即使1atomNUMBER),1也不是函数,因此您无法使用1()之类的函数调用它。我的问题是:给定一个power语法规则的实例,可以将其atom替换为atom中除NAME以外的任何规则的解析树。 Python程序还在运行吗?

编辑(答案):

可以使用()运算符调用任何“可调用”的内容。 (http://docs.python.org/py3k/reference/expressions.html#calls):

call ::=  primary "(" [argument_list [","] | comprehension] ")"
  

primary必须求值为可调用对象(用户定义的函数,内置函数,内置对象的方法,类对象,类实例的方法以及具有{{1}的所有对象}方法是可调用的。)

这意味着您可以执行以下操作:

__call__()

甚至更疯狂(无用)的东西:

>>> eval.__call__.__call__("print(\"x\")")
x

2 个答案:

答案 0 :(得分:7)

>>> 1()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>>

请注意,此处的错误是TypeError,而不是SyntaxError。尝试调用数字是完全合法的语法;数字只是没有任何实际的电话功能

答案 1 :(得分:0)

带括号的子表达式也是可调用的,因为它可能是一个函数,即使没有包含名称:(lambda: 1)()。看看语法,我实际上无法确切地说出它是如何被解析的(它似乎不是yield_exprtestlist_comp,但除了{{1}之外我什么都看不到在任何一个之后坚持使用call-parentheses是有效的。

尽管如此,解析器的工作并不是强制执行语义检查。 atom完全能够被解释为试图在没有参数的情况下调用数字1;是否意味着任何事情取决于口译员。解析器失败是指解释器无法确定代码请求执行哪些操作甚至尝试执行它们的情况。

单挑1()作为唯一合法的函数调用预告片会给语法增加不必要的复杂性,实际上没有什么好处。 Python已经有一个非常好的机制来报告尝试调用无法调用的东西的错误,并且该机制是运行时异常。运行时异常总是必须存在,因为有很多名称绑定到不可调用的东西上,所以在任何地方使用相同的机制只会减少概念开销。

在Python程序员的层面上也会有点反直觉。在我内化的思考Python语法的方式中,还有其他一些非语法名称,这些名称在调用时是完全合理的,例如:

NAME

恰好碰巧这些都没有被解析为result()() dict_of_funcs[name]() (因为它们被解析为单个atom后跟多个atom s)但这不是我的方式关于Python语言,我只是想“你可以调用任何表达式”(模数优先级规则可能需要添加括号),并且根据这种理解,我会感到惊讶的是无法调用一个整数或一个字符串(特别是因为我可以当它是一个名字而不是一个文字)。

这也会使语言语义的更改变得更加困难。想象一下假设未来的语言变化,其中调用字典被定义为与查找键相同,这样我就可以编写trailer。根据当前的语法,所有必要的是为内置{1: 'foo'}(1)类型实现等效的__call__。如果只有dict而不是其他原子可能有NAME预告片,那么这会引入一个不一致的地方,即无法调用文字'(' [arglist] ')'值,但是绑定到{{1可以调用value。像dict一样好但dict不正确的情况已经存在的不一致性,但由于存在像x.__class__这样的浮点文字,这基本上只是妥协。没有类似的情况使1.__class__语法无效,而不仅仅是异常提升操作。