2

I'm new to both Python and PyCharm, so please forgive ignorance.

I was trying to tech myself about the execution of functions when initialising classes - specifically, I want to re-use a database connection object if passed into a new instance, but create one if not. I have a function get_cnx() that creates a connection. I discovered that, whether using a default argument in the __init__ statement to call get_cnx():

def __init__(self, db_cnx=get_cnx())

...or whether using a keyword argument:

self.db_cnx = kwargs.get('db_cnx', get_cnx())

...the function is always executed regardless of the presence (or content) of the connection argument that's passed in. Defeats the object of re-using a connection, so I reverted to an if condition. I believe there's a way of doing this with a decorator, but that felt like gilding the Lilly.

Anyway, this is the context for my actual question: to help me work out what was going on I created this simple test, as a module called "classes.py":

greeting = 'Good Day'


def my_func():
    global greeting
    greeting = 'Changed'
    return 'Hello'


class Animal:
    def __init__(self, greet):
        if not greet:
            self.greet = my_func()
        else:
            self.greet = greet


if __name__ == '__main__':
    cat = Animal(None)

If I run this module (with "Run with Python console" checked in the configuration), I see the global variable greeting shown in blue as 'Changed', which is what I'd expect.

If I change the last bit to this:

if __name__ == '__main__':
    cat = Animal('Wotcha')

I see the global variable shown in blue as 'Good Day', which is also what I'd expect.

However, when I then type this into the console:

dog = Animal(None)

...the global variable name turns red but still shows 'Good Day'.

Similarly, using the PyCharm console does the same thing:

>>> print(greeting)
Good Day
>>> dog = Animal(None)
>>> print(greeting)
Good Day

Now, I loaded the module into IDLE and hit F5 (run module), and in the console, did this:

>>> greeting
'Good Day'
>>> dog = Animal(None)
>>> greeting
'Changed'

This is what I would have expected to see in the PyCharm console.

Can someone explain what's going on? Could it be a bug, or is it my lack of understanding of the way PyCharm deals with scope? Or my lack of broader understanding of execution scope?

Thanks!!

enjayaitch
  • 137
  • 1
  • 9
  • Might have answered my own question from the top (excellent) answer to this: https://stackoverflow.com/questions/15959534/python-visibility-of-global-variables-in-imported-modules. It seems that when you "run" a module in PyCharm it's actually doing a "from import *", whereas "running" a module in IDLE is like executing the code line-by-line in the interpreter. This explains the behaviour of the global variables, which are actually copies of variables created at the point of execution. – enjayaitch Jul 20 '18 at 11:48
  • edit to the above - probably inaccurate to say the "run" is equivalent to a `from import *`. If it were, it wouldn't execute the `if __name__ = '__main__'` block, which of course it does. But it's as if, once it's executed that and leaves the console running, subsequent interpreter commands do not reference the module global variable, but a copy of them taken at a point in time (as though it had executed `from import *`. – enjayaitch Jul 20 '18 at 14:19

1 Answers1

1

JetBrains have opened a bug report for me - confirmed the behaviour isn't as expected.

enjayaitch
  • 137
  • 1
  • 9