Stumpokapow
listen to the mad man
Ran into a fun python (2.7) bug/feature today.
Python has an extremely limited number of special built-in functions called built-ins. Other than that everything works through a module system that has a bunch of sensible, coherent namespace rules. What you need to know for this example is that the mathematical max function is called max and it's one of these special built-ins.
Let's do some basic sanity checking:
This returns 3.
This creates an int called max, overloading the previous symbol definition for the builtin, so in the current scope, I can no longer call the max function. If this had errored, I wouldn't blame it, not wanting people to override builtins would be a reasonable conceit.
If I try to call it again in the same code environment, I get an error, because int type objects are not callables. This is what I would expect.
Okay, now let's clear our environment and run again code from scratch.
This will correctly assign the value 3 to my_var, because the interpreter never gets to the max=4 definition and can run the max(2,3) function as it should.
Now checking if order matters, to see if the interpreter will trip up from seeing the variable before the function call. Okay, this will also correctly assign the value 3 to my_var, because the interpreter never gets to the max=4 definition and can run the max(2,3) function as it should. So as long as the interpreter never executes code that overloads the max() function, I should be able to use it, right?
What do you expect this code will do?
If you guessed
a) Work correctly
b) Fail because an int is not callable
You are incorrect.
The answer is:
c) Fail because max is a local variable of indeterminate type that hasn't yet be defined, so I can't access an undefined variable.
I think what's going on is the Python interpreter doesn't seem to pre-scan code in the global interpreter space, so the stuff outside the function works fine. But when you put code inside the function, before it runs any of the function, it does some sort of static analysis to pre-populate the local variable scope space, hitting the line that defines max, and noting in advance that it expects max to be a variable, which then causes the line that does run to fail.
Or else, global variables are pre-analyzed, but lower in the lookup table hierarchy than global built-ins, but local variables are somehow higher in the lookup table than global built-ins.
Either way, it's an unusual scoping and allocation behaviour.
Python has an extremely limited number of special built-in functions called built-ins. Other than that everything works through a module system that has a bunch of sensible, coherent namespace rules. What you need to know for this example is that the mathematical max function is called max and it's one of these special built-ins.
Let's do some basic sanity checking:
Code:
max(2,3)
Code:
max=3
Code:
max(2,3)
Okay, now let's clear our environment and run again code from scratch.
Code:
if True:
my_var = max(2,3)
else:
max = 4
Code:
if False:
max=4
else:
my_var = max(2,3)
What do you expect this code will do?
Code:
def test():
if True:
my_var = max(2,3)
else:
max = 4
test()
If you guessed
a) Work correctly
b) Fail because an int is not callable
You are incorrect.
The answer is:
c) Fail because max is a local variable of indeterminate type that hasn't yet be defined, so I can't access an undefined variable.
I think what's going on is the Python interpreter doesn't seem to pre-scan code in the global interpreter space, so the stuff outside the function works fine. But when you put code inside the function, before it runs any of the function, it does some sort of static analysis to pre-populate the local variable scope space, hitting the line that defines max, and noting in advance that it expects max to be a variable, which then causes the line that does run to fail.
Or else, global variables are pre-analyzed, but lower in the lookup table hierarchy than global built-ins, but local variables are somehow higher in the lookup table than global built-ins.
Either way, it's an unusual scoping and allocation behaviour.