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

    From Roel Schroeven@roel@roelschroeven.net to comp.lang.python on Wed Mar 6 16:39:09 2024
    From Newsgroup: comp.lang.python

    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.
    --
    "Il semble que la perfection soit atteinte non quand il n'y a plus rien à ajouter, mais quand il n'y a plus rien à retrancher."
    "Perfectie is niet bereikt als er niets meer toe te voegen is, maar als er niets meer weg te nemen is."
    -- Antoine de Saint-Exupéry

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

    Op 6/03/2024 om 16:39 schreef Roel Schroeven via Python-list:
    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.
    (As an aside, I made a type; "What exactly _do_ you mean" is what I
    meant to type)

    If you want, you can play with the code online here: https://tio.run/##pVPbitswEH3XVwwJITaNQ9KllATy0EKhL/2AUsqiWKNkWlkykrzZ7NJvT0e@JWT7VmPsEZozc87RqD7Ho7MPl8sUQpQ@QukUCqG9q0DJiJEqBKpqx1vDegHp@@JsHyk0UfaY0tXnIT/FQogpkKVI0lBAcJ4OZKWBJ2kaDEKo@IjPNfkz7MYGyxB9nYJsst58XBWrNb@wWm1Xq8kCJrPvxawqZgpmX7ezb5N86bE2ssQsvpDVbjewWzaxzIUwjxFD5PI/1gt4v4CHn0xKoQblHilm@VYAPwfj9kxrpLOAHjcFGX6jgrp1CqIDjxp9CnrMk/Qk9wYDaOdh7@JRtCUTMtDBgsVTp5edYbuIZZpzl/NP@dadsvzdaG1WkW2Yy@5D3mJqTzZmIzK5pTu37p3JmcOvhkUw2XB0pxsmRxlgj2h7jqh6ygcv990pOg18ZLEV5bFo0ulpoIhVaHOTP1XNvFN21rmV91W0M8adyB64hEWoUNowGHoiY8CwVg/sp8coyQ722MHTwEWRCZYy9SVGMd9KWqqbBFWcGkgh6MaWkbgOryNKlSi2igdZV8kj6RCXpUHps4FtPz/X4QwYU6F@RlNSMoESv071digk6xqtymgoJVXXMdl027DP22xyvg8cpfLt/I0KRL@RLiDwhHanPP@M3Brn@bAu2mdc6/k4B7vXMfxzs98R2L12/@tOPrb48owlz1fH575TMTbsr8sb@CfNR3kH@x9@l8tf

    (sorry for the long URL; that's where tio.run puts the code)

    Again it works as expected, but with or without the l_test.clear() line.
    --
    "Il semble que la perfection soit atteinte non quand il n'y a plus rien à ajouter, mais quand il n'y a plus rien à retrancher."
    "Perfectie is niet bereikt als er niets meer toe te voegen is, maar als er niets meer weg te nemen is."
    -- Antoine de Saint-Exupéry

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

    Matt, other mail is more relevant - seems to maybe have more to do with different behavour if import code, or not - no, does not make sense to
    me - but, here's the command line contents including printing out id() results, but, only working via importing code:

    #---start 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("date value", dt_expiry.strftime("%Y-%m-%d %H:%M"))
        print("ID", id(dt_expiry))
    # 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
    print(id(dt_expiry))
    1808577867152
    do_it()
    date value 2024-03-06 18:39
    ID 1808572660736
    print(dt_expiry)
    1970-01-01 00:00:00+00:00
    print(id(dt_expiry))
    1808577867152

    ---end session---

    As in, the two different ID values are being returned outside and inside
    the function, whereas, if I included that bit inside the interpreter
    while typing code manually, chances are the same ID would be retained
    both inside and outside function.

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


    On 2024/03/06 15:57, Mats Wichmann via Python-list wrote:
    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 Grant Edwards@grant.b.edwards@gmail.com to comp.lang.python on Wed Mar 6 20:55:40 2024
    From Newsgroup: comp.lang.python

    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