Changing list items and changing the list itself
I have a question about variable scope, I tried to find an answer here and I have a similar but still a bit confusing here Function changelog values, not variable values in Python
So the code looks like this:
position = [50, 50]
# Handler for timer
def tick():
x = random.randrange(0, width)
y = random.randrange(0, height)
position[0] = x
position[1] = y
Is that why I don't need to add a "global position" to change the variable position elements?
source to share
The addition global position
would only be necessary if you assigned a global position variable to reference the new list (without a global declaration, the position will be written to the locals for this function).
In your situation, all you do is search for the position of the global variable to find the list it refers to. Then you update this list in place.
Here is a Python mentor visualization that displays all the options (assign to local, assign to global, update the list referenced by the global).
Also, take a look at Ned Batchelder's excellent blog post that fully explains the python-pass-by-object pass mechanism.
source to share
From the documentation about names and bindings -
If a variable is used in a code block but is not defined there , it is a free variable.
From the global operator documentation -
A global statement is a declaration that is executed for the entire current block of code. This means that the listed identifiers must be interpreted as global. It is not possible to assign a global variable without globals, although free variables can refer to global variables without being declared global.
(Emphasis mine)
When you do -
position[0] = <something>
You are not defining anything, you are mutating an already defined position
inplace list (by changing its 0th element to refer to something else).
Suppose if it has position
n't been defined ever when you do something like
position[0] = 1
You will receive NameError
-
>>> position[0] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'position' is not defined
This is why, in spite of what you do postion[0] = <something>
, its still a free variable, as it is not defined in the block and therefore is treated as global.
UPDATE :
Additional information when you do -
position[0] = <something>
This is not a simple statementassignment
, its actually an extended assignment operator .
source to share
You need to apply two concepts to understand the code
- Python Object Model
- Scoping
First, the Scope Rules:
Following is the hierarchy of variable definition rules for variables
- Local scope - inside a function
- Enclosing - inside any or all of the closing function
- Global - top level module (file)
- Built-in - any built-in modules that are imported
Python Object Model:
In Python, everything is an object. When the say variable is declared x = 1000
, the following steps are performed
- An int object with the value 1000 is created
- object reference created
x
-
x
points to this integer object
Now, when the statement position[0] = x
is executed internally tick()
, the statement has no purpose only for initialization. Since position
it is not defined within the scope of a function, it searches in the order of the hierarchy of scoping rules - scope (parent function) followed by Scope module (file) followed by BuiltIn modules. Here it finds the variable in the global scope and updates it.
In case your statement is position = [100, 100]
, a new list object is created and a new object reference is created within the scope of tick () and does the assignment
If you have a statement global position
, it tells Python that the variable in the Global Scope is the same as the variable in the Local Scope. It then position = [100,100]
creates a list object [100,100]
and binds its global variable position
to the new list object.
source to share