• Re: Variable scope inside and outside functions - global statementbeing overridden by assignation unless preceded by reference

    From dn@PythonList@DancesWithMice.info to comp.lang.python on Wed Mar 6 07:23:41 2024
    From Newsgroup: comp.lang.python

    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..."


    --
    Regards,
    =dn
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Cameron Simpson@cs@cskk.id.au to comp.lang.python on Wed Mar 6 08:20:00 2024
    From Newsgroup: comp.lang.python

    On 05Mar2024 20:13, Jacob Kruger <jacob.kruger.work@gmail.com> wrote:
    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 .

    Because there are no variable definitions in Python, when you write a
    function Python does a static analysis of it to decide which variables
    are local and which are not. If there's an assignment to a variable, it
    is a local variable. _Regardless_ of whether that assignment has been executed, or gets executed at all (eg in an if-statement branch which
    doesn't fire).

    You can use `global` or `nonlocal` to change where Python looks for a particular name.

    In the code below, `f1` has no local variables and `f2` has an `x` and
    `l1` local variable.

    x = 1
    l1 = [1, 2, 3]

    def f1():
    print("f1 ...")
    l1[1] = 5 # _not_ an assignment to "l1"
    print("in f1, x =", x, "l1 =", l1)

    def f2():
    print("f2 ...")
    x = 3
    l1 = [6, 7, 9] # assignment to "l1"
    print("in f2, x =", x, "l1 =", l1)

    print("outside, x =", x, "l1 =", l1)
    f1()
    print("outside after f1, x =", x, "l1 =", l1)
    f2()
    print("outside after f2, x =", x, "l1 =", l1)

    Cheers,
    Cameron Simpson <cs@cskk.id.au>
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Grant Edwards@grant.b.edwards@gmail.com to comp.lang.python on Tue Mar 5 17:46:32 2024
    From Newsgroup: comp.lang.python

    On 2024-03-05, Cameron Simpson via Python-list <python-list@python.org> wrote:

    Because there are no variable definitions in Python, when you write
    a function Python does a static analysis of it to decide which
    variables are local and which are not. If there's an assignment to a variable, it is a local variable. _Regardless_ of whether that
    assignment has been executed, or gets executed at all (eg in an
    if-statement branch which doesn't fire).

    Unfortunately, crap "information" sites like geeksforgeeks often
    describe this either incorrectly or so vaguely as to be worthless.
    From the page https://www.geeksforgeeks.org/global-local-variables-python/

    Python Global variables are those which are not defined inside
    any function and have a global scope whereas Python local
    variables are those which are defined inside a function and their
    scope is limited to that function only.

    Since "define" (in this context) isn't a term of art in Python, and
    it's never defined on the page in question, the quoted paragraph is
    not meaningful: it simply says that "global variables are global and
    local variables are local".

    That page goes on to say:

    In other words, we can say that local variables are accessible
    only inside the function in which it was initialized

    This is equally crap. It doesn't matter whether the variable is
    initialized or not. As Cameron correctly stated, if a function
    contains an assignment to a variable, and that variable is not
    declared global, then that variable is local. For example:

    def foo():
    print(s)
    if 0:
    s = "there"
    print(s)

    In the function above s _is_not_ initialized in the function foo().
    However, foo() does contain an assignment to s, therefore s is local
    unless declared global/nonlocal. [And the first print() will throw an exception even if there is a value bound to the global name 's'.]

    Unfortunately (presumably thanks to SEO) the enshittification of
    Google has reached the point where searching for info on things like
    Python name scope, the first page of links are to worthless sites like geeksforgeeks.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Alan Gauld@learn2program@gmail.com to comp.lang.python on Wed Mar 6 10:59:38 2024
    From Newsgroup: comp.lang.python

    On 05/03/2024 22:46, Grant Edwards via Python-list wrote:
    Unfortunately (presumably thanks to SEO) the enshittification of
    Google has reached the point where searching for info on things like
    Python name scope, the first page of links are to worthless sites like geeksforgeeks.
    And not just Google, I just tried bing, yahoo and duckduckgo
    and they are all the same. Not a one listed anything from
    python.org on the first page... In fact it didn't even appear
    in the first 100 listings, although wikipedia did manage an
    entry, eventually.
    --
    Alan G
    Author of the Learn to Program web site
    http://www.alan-g.me.uk/
    http://www.amazon.com/author/alan_gauld
    Follow my photo-blog on Flickr at:
    http://www.flickr.com/photos/alangauldphotos


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Jacob Kruger@jacob.kruger.work@gmail.com to comp.lang.python on Wed Mar 6 14:55:46 2024
    From Newsgroup: comp.lang.python

    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..."



    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Jacob Kruger@jacob.kruger.work@gmail.com to comp.lang.python on Wed Mar 6 15:12:46 2024
    From Newsgroup: comp.lang.python

    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..."



    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Mats Wichmann@mats@wichmann.us to comp.lang.python on Wed Mar 6 06:57:01 2024
    From Newsgroup: comp.lang.python

    On 3/6/24 05:55, 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:

    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

    No, it doesn't. Your code is working as one would expect. For example,
    adding prints for the l_test variable, and removing the .clear() which
    you claim makes it not work, shows me:

    before: l_test=[1, 2, 3], id(l_test)=140153285385856
    leaving do_it: l_test=[1, 2, 3, 1, 2, 3, 99], id(l_test)=140153285385856
    after: l_test=[1, 2, 3, 1, 2, 3, 99], id(l_test)=140153285385856

    It's the same list object, as you can see by the id values. And the list
    is updating as expected.

    And... you don't need the global statement for l_test. As it's mutable,
    you can mutate it in the function; the global only acts on assignment.
    Using "global" for that may make your intent more clear to readers
    though, although static checkers will grumble at you.

    You must be doing something additional that you're not telling us about.


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Thomas Passin@list1@tompassin.net to comp.lang.python on Wed Mar 6 08:16:01 2024
    From Newsgroup: comp.lang.python

    On 3/6/2024 5:59 AM, Alan Gauld via Python-list wrote:
    On 05/03/2024 22:46, Grant Edwards via Python-list wrote:
    Unfortunately (presumably thanks to SEO) the enshittification of
    Google has reached the point where searching for info on things like
    Python name scope, the first page of links are to worthless sites like
    geeksforgeeks.
    And not just Google, I just tried bing, yahoo and duckduckgo
    and they are all the same. Not a one listed anything from
    python.org on the first page... In fact it didn't even appear
    in the first 100 listings, although wikipedia did manage an
    entry, eventually.

    I don't know ... I just searched for "python local vs global variables"
    and a python.org page on it was the second hit. I usually use StartPage
    - who knows where they aggregate from - but the same search on Google
    and Bing also popped up the python.org link as the second hit. As usual
    Bing was a nasty experience, though.

    Still, if your search phrase isn't as well focused as that or you are
    less lucky, for sure you'll get all sorts of junk.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Thomas Passin@list1@tompassin.net to comp.lang.python on Wed Mar 6 09:01:44 2024
    From Newsgroup: comp.lang.python

    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..."




    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Jacob Kruger@jacob.kruger.work@gmail.com to comp.lang.python on Wed Mar 6 18:28:59 2024
    From Newsgroup: comp.lang.python

    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..."




    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Jacob Kruger@jacob.kruger.work@gmail.com to comp.lang.python on Wed Mar 6 18:50:31 2024
    From Newsgroup: comp.lang.python

    You'll see more details in other mail, but, here I am firing up standard python interpreter from within windows terminal, and then executing
    following line:

    from scoping2 import *


    And, this is under windows 11 windows terminal, which is where I
    generally interact with my python code, via command line - generally
    working with flask, and/or other forms of command line interaction, most
    of the time.


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


    On 2024/03/06 17:39, Roel Schroeven via Python-list wrote:
    Op 6/03/2024 om 13:55 schreef Jacob Kruger via Python-list:
    If you import the contents of that file into the python interpreter,
    [...]

    What exactly to you mean by "import the contents of that file into the python interpreter"? Other people have put your code in a script,
    executed it, and saw it working as expected. I pasted in IPython, and likewise saw it working as expected, and the same with IDLE. It seems
    to me you must be doing something different from us; maybe the way you execute that code might be the key to this whole confusion.

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Ethan Furman@ethan@stoneleaf.us to comp.lang.python on Wed Mar 6 08:57:27 2024
    From Newsgroup: comp.lang.python

    On 3/6/24 08:28, Jacob Kruger via Python-list wrote:

    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 *

    And it becomes clear: only do `from ... import *` when the module has been specifically designed to support that.

    If you were to also do `import scoping2` and, after calling `do_it()`, `print(scoping2.dt_expiry)`, you would see that
    it had changed.

    I know there are good explanations for how variables and names work in Python, but I couldn't find any at the moment.
    Sorry.

    --
    ~Ethan~
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Jacob Kruger@jacob.kruger.work@gmail.com to comp.lang.python on Wed Mar 6 19:29:12 2024
    From Newsgroup: comp.lang.python

    Ok, Ethan, that makes sense - I generally work with modules in folders,
    etc., but, this was just test code, but, 'see' if I instead import
    scoping2 as sc2, and then refer to sc2.dt_expiry and sc2.do_it, then it
    does operate as it should - thanks, again.


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


    On 2024/03/06 18:57, Ethan Furman via Python-list wrote:
    On 3/6/24 08:28, Jacob Kruger via Python-list wrote:

    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 *

    And it becomes clear:  only do `from ... import *` when the module has
    been specifically designed to support that.

    If you were to also do `import scoping2` and, after calling `do_it()`, `print(scoping2.dt_expiry)`, you would see that it had changed.

    I know there are good explanations for how variables and names work in Python, but I couldn't find any at the moment. Sorry.

    --
    ~Ethan~
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Roel Schroeven@roel@roelschroeven.net to comp.lang.python on Wed Mar 6 18:33:17 2024
    From Newsgroup: comp.lang.python

    Op 6/03/2024 om 17:40 schreef Jacob Kruger via Python-list:
    from scoping2 import *
    Ah yes, that explains what's happening. After that statement, the name dt_expiry in the current namespace is bound to the same object that the
    name dt_expiry in the namespace of module scoping2 is bound to. Function
    do_it re-binds that last one to a new one, with the new value; name
    dt_expiry in the current namespace is still bound to the old object. (If
    all of that sounds like gibberish, have a look at "Facts and myths about Python names and values" (text:
    https://nedbatchelder.com/text/names.html; slides and video: https://nedbatchelder.com/text/names1.html)

    I would advice not to use 'import *', if at all possible, for multiple reasons, one of which is to prevent problems like this.

    I would also advice not to use global variables from other modules
    directly, and in fact would advice to minimize the use of globals in
    general as much as possible. If you need to keep state between methods,
    it might be better to use a class.
    --
    "There is a theory which states that if ever anyone discovers exactly what the Universe is for and why it is here, it will instantly disappear and be
    replaced by something even more bizarre and inexplicable.
    There is another theory which states that this has already happened."
    -- Douglas Adams, The Restaurant at the End of the Universe

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Grant Edwards@grant.b.edwards@gmail.com to comp.lang.python on Wed Mar 6 12:59:38 2024
    From Newsgroup: comp.lang.python

    On 2024-03-06, Roel Schroeven via Python-list <python-list@python.org> wrote:
    Op 6/03/2024 om 17:40 schreef Jacob Kruger via Python-list:
    from scoping2 import *

    [...]

    I would advice not to use 'import *', if at all possible, for multiple reasons, one of which is to prevent problems like this.

    Unfortunately, many (most?) tutorials for particular modules (and even
    example code in the Python documentation itself) are all written
    assuming that you do "from <module> import *". It saves the tutorial
    write a few keystrokes, but causes untold trouble for people who learn incorrectly that "from <module> import *" is the proper way to do
    things.

    I would also advice not to use global variables from other modules
    directly, and in fact would advice to minimize the use of globals in
    general as much as possible. If you need to keep state between
    methods, it might be better to use a class.


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Roel Schroeven@roel@roelschroeven.net to comp.lang.python on Wed Mar 6 19:28:29 2024
    From Newsgroup: comp.lang.python



    Grant Edwards via Python-list schreef op 6/03/2024 om 18:59:
    On 2024-03-06, Roel Schroeven via Python-list <python-list@python.org> wrote:
    Op 6/03/2024 om 17:40 schreef Jacob Kruger via Python-list:
    from scoping2 import *

    [...]

    I would advice not to use 'import *', if at all possible, for
    multiple > reasons, one of which is to prevent problems like this.

    Unfortunately, many (most?) tutorials for particular modules (and even example code in the Python documentation itself) are all written
    assuming that you do "from <module> import *". It saves the tutorial
    write a few keystrokes, but causes untold trouble for people who learn incorrectly that "from <module> import *" is the proper way to do
    things.

    I know ... it's really irritating.
    --
    "There is a theory which states that if ever anyone discovers exactly what the Universe is for and why it is here, it will instantly disappear and be
    replaced by something even more bizarre and inexplicable.
    There is another theory which states that this has already happened."
    -- Douglas Adams, The Restaurant at the End of the Universe

    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From dn@PythonList@DancesWithMice.info to comp.lang.python on Thu Mar 7 14:10:11 2024
    From Newsgroup: comp.lang.python

    On 7/03/24 05:28, Jacob Kruger via Python-list wrote:
    ...
    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.?
    Some of the facts, such as HOW the code was being executed were missing
    (see earlier request for a cut-down scenario, AND reports from others
    saying 'but it works for me').

    The idea of importing a module into the REPL and then (repeatedly)
    manually entering the code to set-up and execute is unusual (surely type
    such into a script (once), and run that (repeatedly). As you say, most
    of us would be working from an IDE and hitting 'Run'. Am wondering why
    you weren't - but it's not important.

    That said, the REPL is the perfect place to learn, experiment, and
    prototype - particularly when compared with the facilities of other
    language's eco-systems. The entirety of the on-line Tutorial cannot be
    wrong! (although, after a quick review, I've failed to see where the
    Tutorial mentions the usual development mode, apart from two very brief
    asides (the most useful is almost at the very end(?)) - but then (as
    they say) the objective is to show the language!

    The lesson-learned is that there are different 'environments' and
    different ways of building the environment in which the code will run.
    That's a valuable lesson, and full of subtlety!

    Glad to see that comparing id()s was useful - for diagnosis but not
    solution. Other tools might include the locals() and globals()
    functions. You may also have detected that many of us try to avoid
    globals and the implicit assumptions about the behavior of mutable
    collections (eg lists) when treated as 'global'. Then there are
    "closures", the "LEGB" rule, namespaces, scope, and ...
    --
    --
    Regards,
    =dn
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Jacob Kruger@jacob.kruger.work@gmail.com to comp.lang.python on Thu Mar 7 10:23:27 2024
    From Newsgroup: comp.lang.python

    Thanks again, all.


    I think the python -i scoping2.py would have given me a good beginning
    as well - will archive that one for use.


    And, to maybe explain how I work - not an excuse at all - but, I am
    actually 100% blind, so a lot of the IDE's, or their common
    means/methods of interaction don't suit me all the time, which is why I generally work via programmer's text editor interfaces, or treat
    something like VS code as such, but then still prefer to run my code via command line, using pdb to then play around with forms of debugging, etc.


    And, yes, also generally prefer to work via classes, modules, etc. at
    runtime, but this was more or less mostly testing, which then caused confusion/interference on my side...LOL!


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


    On 2024/03/07 03:55, Grant Edwards via Python-list wrote:
    On 2024-03-07, dn via Python-list <python-list@python.org> wrote:

    The idea of importing a module into the REPL and then (repeatedly)
    manually entering the code to set-up and execute is unusual (surely type
    such into a script (once), and run that (repeatedly). As you say, most
    of us would be working from an IDE and hitting 'Run'. Am wondering why
    you weren't - but it's not important.
    Unless the code is intended to be used as a module, 'import'ing it into
    the REPL doesn't make sense.

    A simple example:

    ---------------------------testit.py------------------------------
    x = 'x'
    y = 'y'
    def foo():
    global y
    print("hi")
    x = 'X'
    y = 'Y'
    print(x)
    print(y) ------------------------------------------------------------------

    The usual method to play with that interactively is

    $ python -i testit.py
    >>> x
    'x'
    >>> y
    'y'
    >>> foo()
    hi
    X
    Y
    >>> x
    'x'
    >>> y
    'Y'
    >>>

    As we've seen, doing a 'from testit.py import *' doesn't let you test
    what the OP was trying to test. Doing 'import testit.py' gets you
    closer, but it's a hassle to test code that way. The right thing to do
    is 'python -i <filename>' (or the equivalent button/option in an IDE).

    https://docs.python.org/3/tutorial/interpreter.html

    If you intended to use testit.py as a module, and wanted to experiment
    with its behavior as a module, then go ahead and import it. But, don't
    do 'from testit.py import *' until

    1. you know how that differs from 'import testit.py'

    and

    2. you want to use that difference


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Cameron Simpson@cs@cskk.id.au to comp.lang.python on Fri Mar 8 09:48:08 2024
    From Newsgroup: comp.lang.python

    On 06Mar2024 15:12, Jacob Kruger <jacob.kruger.work@gmail.com> wrote:
    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?

    Yes. Note that the "global" namespace is the module in which the
    function is defined.

    x = 1

    def f(n):
    global x
    x += n

    This updates the `x` global variable in the module where `f` was
    defined.

    If you import `f` and use it in another module it will _still_ update
    `x` in the original module namespace.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Grant Edwards@grant.b.edwards@gmail.com to comp.lang.python on Fri Mar 8 08:49:24 2024
    From Newsgroup: comp.lang.python

    On 2024-03-07, Cameron Simpson via Python-list <python-list@python.org> wrote:

    Yes. Note that the "global" namespace is the module in which the
    function is defined.

    One might argue that "global" isn't a good choice for what to call the
    scope in question, since it's not global. It's limited to that source
    file. It doesn't make sense to me to call a binding "global", when
    there can be multile different "global" bindings of the same name.

    --
    Grant




    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Chris Angelico@rosuav@gmail.com to comp.lang.python on Sat Mar 9 00:57:40 2024
    From Newsgroup: comp.lang.python

    On Sat, 9 Mar 2024 at 00:51, Grant Edwards via Python-list <python-list@python.org> wrote:
    One might argue that "global" isn't a good choice for what to call the
    scope in question, since it's not global. It's limited to that source
    file. It doesn't make sense to me to call a binding "global", when
    there can be multile different "global" bindings of the same name.


    Most "globals" aren't global either, since you can have different
    globals in different running applications.

    ChrisA
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Grant Edwards@grant.b.edwards@gmail.com to comp.lang.python on Fri Mar 8 11:41:10 2024
    From Newsgroup: comp.lang.python

    On 2024-03-08, Chris Angelico via Python-list <python-list@python.org> wrote:
    On Sat, 9 Mar 2024 at 00:51, Grant Edwards via Python-list
    <python-list@python.org> wrote:

    One might argue that "global" isn't a good choice for what to call the
    scope in question, since it's not global. It's limited to that source
    file. It doesn't make sense to me to call a binding "global", when
    there can be multile different "global" bindings of the same name.

    Most "globals" aren't global either, since you can have different
    globals in different running applications.

    To me, "global" has always been limited to within a single
    process/address space, but that's probably just bias left over from C/Pascal/FORTRAN/assembly/etc. It never occurred to me that a global
    called "X" in one program on one computer would be the same as a
    global called "X" in a different program on a different computer
    somewhere else on the "globe".


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Chris Angelico@rosuav@gmail.com to comp.lang.python on Sat Mar 9 08:30:53 2024
    From Newsgroup: comp.lang.python

    On Sat, 9 Mar 2024 at 03:42, Grant Edwards via Python-list <python-list@python.org> wrote:

    On 2024-03-08, Chris Angelico via Python-list <python-list@python.org> wrote:
    On Sat, 9 Mar 2024 at 00:51, Grant Edwards via Python-list
    <python-list@python.org> wrote:

    One might argue that "global" isn't a good choice for what to call the
    scope in question, since it's not global. It's limited to that source
    file. It doesn't make sense to me to call a binding "global", when
    there can be multile different "global" bindings of the same name.

    Most "globals" aren't global either, since you can have different
    globals in different running applications.

    To me, "global" has always been limited to within a single
    process/address space, but that's probably just bias left over from C/Pascal/FORTRAN/assembly/etc. It never occurred to me that a global
    called "X" in one program on one computer would be the same as a
    global called "X" in a different program on a different computer
    somewhere else on the "globe".


    Yeah. My point is, though, the name "global" is a bit of a hack
    anyway, so it's not THAT big a deal if it has other caveats too. For
    example, let's say you always "import globals" at the top of every
    script, and then assign "globals.x = 123" etc. Now you have a concept
    of globals that spans the entire application, right? Well, no, not if
    you use multiprocessing.

    So, go ahead and call them globals, but people will always have to
    learn about exactly what that means.

    ChrisA
    --- Synchronet 3.20a-Linux NewsLink 1.114