Variable scope inside and outside functions - global statement being overridden by assignation unless preceded by reference

Jacob Kruger jacob.kruger.work at gmail.com
Wed Mar 6 08:12:46 EST 2024


So, this does not make sense to me in terms of the following snippet 
from the official python docs page:

https://docs.python.org/3/faq/programming.html


"In Python, variables that are only referenced inside a function are 
implicitly global. If a variable is assigned a value anywhere within the 
function’s body, it’s assumed to be a local unless explicitly declared 
as global."


So, I would then assume that if I explicitly include a variable name 
inside the global statement, then even just assigning it a new value 
should update the variable in the global context, outside the function?


Unless this is something that changed from 3.11 to 3.12 - since that 
snippet is more or less referring to 3.12, but, don't think it was 
changed in any way?


Jacob Kruger
+2782 413 4791
"Resistance is futile!...Acceptance is versatile..."


On 2024/03/06 14:55, Jacob Kruger wrote:
> Ok, simpler version - all the code in a simpler test file, and working 
> with two separate variables to explain exactly what am talking about:
>
> # start code
>
> from datetime import datetime, timezone, timedelta
>
> from copy import copy
>
>
> # initialise original values
>
> dt_expiry = datetime.strptime("1970-01-01 00:00", "%Y-%m-%d 
> %H:%M").replace(tzinfo=timezone.utc)
>
> l_test = [1, 2, 3]
>
>
> def do_it():
>     global dt_expiry, l_test # asked python to refer to global 
> variables for both
>
>     # assign new value immediately
>
>     dt_expiry = datetime.now()+timedelta(minutes=5)
>     print(dt_expiry.strftime("%Y-%m-%d %H:%M")) # just to show new 
> value has been assigned
>     # grab copy of list for re-use of items
>     l_temp = copy(l_test)
>     # following line means l_test will later on retain value in global 
> scope because it was manipulated inside function instead of just 
> assigned new value
>     l_test.clear()
>     # replace original set of values
>     for i in l_temp: l_test.append(i)
>     # add new item
>     l_test.append(99)
> # end of do_it function
>
> # end code
>
>
> If you import the contents of that file into the python interpreter, 
> dt_expiry will start off as "1970-01-01 00:00", and, if you execute 
> do_it function, it will print out the new value assigned to the 
> dt_expiry variable inside that function, but if you then again check 
> the value of the dt_expiry variable afterwards, it's reverted to the 
> 1970... value?
>
>
> If I take out the line that removes values from l_test # 
> l_test.clear() # before appending new value to it, then it will also 
> not retain it's new/additional child items after the function exits, 
> and will just revert back to [1, 2, 3] each and every time.
>
>
> In other words, with some of the variable/object types, if you use a 
> function that manipulates the contents of a variable, before then 
> re-assigning it a new value, it seems like it might then actually 
> update/manipulate the global variable, but, either just calling purely 
> content retrieval functions against said objects, or assigning them 
> new values from scratch seems to then ignore the global scope 
> specified in the first line inside the function?
>
>
> Hope this makes more sense
>
>
> Jacob Kruger
> +2782 413 4791
> "Resistance is futile!...Acceptance is versatile..."
>
>
> On 2024/03/05 20:23, dn via Python-list wrote:
>> Jacob,
>>
>> Please reduce the problem to a small code-set which reproduces the 
>> problem. If we can reproduce same, then that tells us something. At 
>> the very least, we can experiment without having to expend amounts of 
>> time in a (likely faulty) bid to reproduce the same environment.
>>
>> Also, code is the ultimate description!
>>
>>
>> Perhaps start with a small experiment:
>>
>> - after l_servers is created, print its id()
>> - after the global statement, print its id()
>> - after the clear/reassignment, print its id()
>>
>> Is Python always working with the same list?
>> Please advise...
>>
>>
>> On 6/03/24 07:13, Jacob Kruger via Python-list wrote:
>>> Hi there
>>>
>>>
>>> Working with python 3.11, and, issue that confused me for a little 
>>> while, trying to figure out what was occurring - unless am 
>>> completely confused, or missing something - was that, for example, 
>>> when having pre-defined a variable, and then included it in the 
>>> global statement inside a function, that function was still 
>>> referring to a completely local instance, without manipulating 
>>> outside variable object at all unless I first executed a form of 
>>> referral to it, before then possibly assigning a new value to it.
>>>
>>>
>>> Now, this does not seem to occur consistently if, for example, I 
>>> just run bare-bones test code inside the python interpreter, but 
>>> consistently occurs inside my actual testing script.
>>>
>>>
>>> Basically, in a file with python code in that am using for a form of
>>> testing at the moment, at the top of the file, under all the import
>>> statements, I initiate the existence of a list variable to make use of
>>>
>>> later:
>>>
>>>
>>> # code snippet
>>>
>>> l_servers = []
>>>
>>> # end of first code snippet
>>>
>>>
>>> Then, lower down, inside a couple of different functions, the first 
>>> line
>>> inside the functions includes the following:
>>> # code snippet
>>>      global l_servers
>>> # end code snippet
>>>
>>> That should, in theory, mean that if I assign a value to that variable
>>> inside one of the functions, it should reflect globally?
>>>
>>> However, it seems like that, while inside those functions, it can be
>>> assigned a new list of values, but if I then return to the scope 
>>> outside
>>>
>>> the functions, it has reverted back to being an empty list = []?
>>>
>>>
>>> The issue seems to specifically (or not) occur when I make a call to 
>>> one function, and, in the steps it's executing in one context, while 
>>> it's not doing anything to the list directly, it's then making a 
>>> call to the second function, which is then meant to repopulate the 
>>> list with a brand new set of values.
>>>
>>>
>>> Now, what almost seems to be occurring, is that while just 
>>> manipulating the contents of a referenced variable is fine in this 
>>> context, the moment I try to reassign it, that's where the issue is 
>>> occurring .
>>>
>>>
>>> Here are relevant excerpts from the file:-
>>>
>>>
>>> # start code
>>>
>>> # original assignation in main part of file
>>>
>>> l_servers = []
>>>
>>>
>>> # function wich is initially being executed
>>>
>>> def interact():
>>>      global l_servers
>>>      # extra code inbetween choosing what to carry out
>>>
>>>      # ...
>>>
>>>      # end of other code
>>>
>>>      bl_response, o_out = list_servers()
>>>
>>>      if bl_response: # just make sure other function call was 
>>> successful
>>>
>>>          l_servers.clear() # first make reference to global variable
>>>
>>>          for srv in o_out: l_servers.append(srv) # now re-populate 
>>> items
>>>
>>>      # end code snippet from inside interact function
>>>
>>> # end of interact function
>>>
>>> # end of code snippet
>>>
>>>
>>> That other function being called from within, list_servers() was 
>>> initially just trying to populate the values inside the global list 
>>> variable itself, but was ending up in a similar fashion - reverting 
>>> to initial empty value, but, the above now seems to work, as long as 
>>> I first make reference to/manipulate/work with global variable 
>>> instead of just trying to reassign it a brand new value/set of items?
>>>
>>>
>>> So, am I missing something obvious, have I forgotten about something 
>>> else - yes, know that if was working from within an embedded 
>>> function, I might need/want to then use the nonlocal statement 
>>> against that variable name, but, honestly, just not sure how this 
>>> can be occurring, and, it's not just with this one list variable, etc.?
>>>
>>>
>>> If I try simple test code from within the python interpreter, using 
>>> different types of variables, this does also not seem to be the same 
>>> all the time, but, don't think it can relate to an iterable like a 
>>> list, or else, just in case, here is the code snippet with all the 
>>> import statements from the top of that file, in case something could 
>>> be overriding standard behaviour - not likely in this context, but, 
>>> really not sure what's occurring:
>>>
>>> # import code snippet
>>>
>>> import requests, time
>>> from requests.auth import HTTPBasicAuth
>>> import psutil as psu
>>> import pytz
>>> import bcrypt
>>> from copy import copy
>>> from datetime import datetime, timedelta, timezone
>>> from dateutil.parser import parse
>>>
>>> # end of import snippet
>>>
>>>
>>> Thanks if you have any ideas/thoughts on the matter
>>>
>>>
>>> Jacob Kruger
>>> +2782 413 4791
>>> "Resistance is futile!...Acceptance is versatile..."
>>>
>>>
>>


More information about the Python-list mailing list