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