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 11:28:59 EST 2024


Thanks for all your input people, and, yes, I know that besides the 
scope oddities the rest of the code is not my normal style either - was 
partly due to forms of experimentation to try figure out what could be 
causing issues. For example, instead of [:] syntax, was specifically 
using copy() to make sure was not interacting with original variable 
values, etc.


This will be a bit longer - copying-pasting command line output here to 
show you what I truly mean - first session, where I am importing code 
into interpreter and second session where I retype exact same code 
behave differently:

#---first session---

C:\temp\py_try>type scoping2.py
from datetime import datetime, timezone, timedelta

dt_expiry = datetime.strptime("1970-01-01 00:00", "%Y-%m-%d 
%H:%M").replace(tzinfo=timezone.utc)

def do_it():
     global dt_expiry
     dt_expiry = datetime.now()+timedelta(minutes=5)
     print(dt_expiry.strftime("%Y-%m-%d %H:%M"))
# end of do_it function

C:\temp\py_try>python
Python 3.11.7 (tags/v3.11.7:fa7a6f2, Dec  4 2023, 19:24:49) [MSC v.1937 
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
 >>> from scoping2 import *
 >>> print(dt_expiry)
1970-01-01 00:00:00+00:00
 >>> do_it()
2024-03-06 18:12
 >>> print(dt_expiry)
1970-01-01 00:00:00+00:00
 >>>

#---end first session---


And, if I now retype the contents of the file into the python 
interpreter instead:

#---start second session---

C:\temp\py_try>python
Python 3.11.7 (tags/v3.11.7:fa7a6f2, Dec  4 2023, 19:24:49) [MSC v.1937 
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
 >>> from datetime import datetime, timezone, timedelta
 >>> dt_expiry = datetime.strptime("1970-01-01 00:00", "%Y-%m-%d 
%H:%M").replace(tzinfo=timezone.utc)
 >>> def do_it():
...     global dt_expiry
...     dt_expiry = datetime.now()+timedelta(minutes=5)
...     print(dt_expiry.strftime("%Y-%m-%d %H:%M"))
...
 >>> print(dt_expiry)
1970-01-01 00:00:00+00:00
 >>> do_it()
2024-03-06 18:20
 >>> print(dt_expiry)
2024-03-06 18:20:03.909825
 >>>

#---end second session---


So, in the second session, where retyped everything, it behaves as I 
would expect it to, but, during first session, the variable is being 
treated as a local variable inside the function - no code differences 
since literally copied-pasted each and every line into console, but, a 
different behaviour nonetheless?


So, yes, know this comes across like some form of a scam/joke, or 
list-garbage, since it doesn't make any sense to me at all, but still 
just wondering if missing something, or should I shift over to 3.12 to 
see if if works differently, or just try reinstalling 3.11 from scratch, 
or should I retry the above in something like the VS code console, or a 
different python console, etc.?


Sorry


Jacob Kruger

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


On 2024/03/06 16:01, Thomas Passin via Python-list wrote:
> On 3/6/2024 7:55 AM, Jacob Kruger via Python-list 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?
>
> Not when I run your code. With a little annotation added to the print 
> statements I get (I added the import statements to make it run, and I 
> used the same date-time formatting for all three print statements):
>
> List before: [1, 2, 3]
> start: 1970-01-01 00:00
> inside after reassignment: 2024-03-06 08:57
> outside after: 2024-03-06 08:57
> List after: [1, 2, 3, 99]
>
> As an aside, you have gone to some trouble to copy, clear, and 
> reconstruct l_test.  It would be simpler like this (and you wouldn't 
> have to import the "copy" library):
>
>     l_temp = l_test[:]
>     l_test = []
>
> Instead of those lines and then this:
>
>     for i in l_temp: l_test.append(i)
>
> you could achieve the same thing with this single statement:
>
>     l_test = l_test[:]
>>
>> 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