Jesus is Lord
Jesus is Lord

Reputation: 15399

Python 3.2 Grammar Specification - Function Call

This is in reference to Python 3.2. Pertinent grammar rules are as follows (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

According to this a basic function call could look like:

atom '(' ')'

But I believe we can't just put any atom in there. For example, even though 1 is an atom (NUMBER), 1 is not a function and therefore you cannot call it with something like 1(). My question is: given an instance of the power grammar rule, could its atom be substituted with any rule of atom's other than NAME in a parse tree of a Python program and still run?

EDIT (ANSWER):

Anything that is "callable" may be called with the () operator. (http://docs.python.org/py3k/reference/expressions.html#calls):

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

The primary must evaluate to a callable object (user-defined functions, built-in functions, methods of built-in objects, class objects, methods of class instances, and all objects having a __call__() method are callable).

This means you can do stuff like:

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

Or even crazier (useless) stuff:

>>> a = lambda x : [abs, lambda y : y][0 if x < 0 else 1](x)
>>> a(1)
1
>>> a(-1)
1
>>> a(0)
0

Upvotes: 1

Views: 884

Answers (2)

Ben
Ben

Reputation: 71485

A parenthesised sub-expression is also callable, because it may be a function, even without containing a name: (lambda: 1)(). Looking at the grammar I can't actually tell exactly how that's parsed (it doesn't seem to be either a yield_expr or a testlist_comp, but I can't see anything other than an atom that's valid to stick call-parentheses after either).

Regardless though, it's not the job of the parser to enforce semantic checks. 1() is perfectly able to be interpreted as an attempt to call the number 1 with no arguments; whether that means anything or not is up to the interpreter. Parser failures are for cases when the interpreter isn't able to figure out what operations the code is requesting to even attempt to carry them out.

Singling out NAME as the only thing that's legal to have a function call trailer would add unnecessary complexity to the grammar for little real benefit. Python already has a perfectly good mechanism for reporting the error of trying to call something that can't be called, and that mechanism is a runtime exception. The runtime exception would always have to exist because there are plenty of names bound to things that are not callable, so it's just less conceptual overhead to use the same mechanism everywhere.

It would be a bit counter-intuitive at the level of the Python programmer, too. In my internalised way of thinking about Python syntax, there are other things that aren't syntactically names that are perfectly reasonable to call, such as the following:

result()()
dict_of_funcs[name]()

It just so happens that none of these are parsed as an atom (because they're rather parsed as a single atom followed by multiple trailers) but that's not how I think about the Python language, I just think "you can call anything that's an expression" (modulo precedence rules that may require the addition of parentheses), and under that understanding I would be surprised to be unable to call an integer or a string (especially since I can when it's a name rather than a literal).

It would also make changing the language semantics more difficult. Imagine a hypothetical future change to the language where calling a dictionary is defined to be the same as looking up a key, so that I could write {1: 'foo'}(1). Under the current grammar, all that would be necessary would be to implement the equivalent of __call__ for the built-in dict type. If only NAME and not other atoms could have the '(' [arglist] ')' trailer, then this would introduce an inconsistency where a literal dict value could not be called, but a name bound to a dict value could be called. An inconsistency much like that already exists where x.__class__ is fine but 1.__class__ is not, but that's basically just compromise due to the existence of floating point literals like 1.0. There's no similar case for making 1() invalid syntax rather than just an exception-raising operation.

Upvotes: 0

Amber
Amber

Reputation: 526613

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

Notice that the error here is a TypeError and not a SyntaxError. It is perfectly legal syntax to try to call a number; numbers just don't have any actual call functionality.

Upvotes: 7

Related Questions