In Python, functions are data, and typing is dynamic. This means that the following lines are valid Python:
def func(x):
return x + 3
func = 3
func
is now an int. The original function func
is no longer referenced. The fact that func
was originally a function doesn't have any bearing on what types of data can be assigned to it in the future. (This is what "dynamic typing" means.)
Therefore, since there's no static typing, and "function" is a valid data type, it wouldn't make sense for the Python interpreter to distinguish between a function and a piece of data referenced by the same name. Therefore, within a given scope, there's no way to use the same unqualified variable name to mean two different things.
In your particular case, if the code in your xplus1
function meant anything, it would mean "compute the value of xplusy(x,1)
and assign that value to the variable xplusy
-- thereby losing the reference to the function xplusy
." However, within the scope of a function, the interpreter won't let you make an assignment to a variable outside of that scope, so it assumes that by writing an assignment statement, you're introducing a new local variable xplusy
. The local variable, however, hasn't been defined yet, so your attempt to call it, xplusy(x,1)
, fails. The globally defined function is not called as a fall-back because, again, you can't have two unqualified names be identical and point to different data in the same scope.
Another example demonstrating the "no duplication of variable names within one scope" rule (which I actually only just discovered while playing around with the prompt in my attempt to construct this answer):
>>> def f1():
... a = xplusy(3,4)
... xplusy = 5
... print xplusy
...
>>> f1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f1
UnboundLocalError: local variable 'xplusy' referenced before assignment
>>> def f1():
... a = xplusy(3,4)
... print a
...
>>> f1()
7
This demonstrates that it really is the scope, not the statement that requires unique names.
EDIT: This is a really cool post that explains this and other scoping-related behavior: http://me.veekun.com/blog/2011/04/24/gotcha-python-scoping-closures/