Behaviour of global variables in "run with Python console"
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.
Anyway, in the course of working this out 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 if I type 'greeting' into the console it returns the same result.
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?
Thanks!!
Please sign in to leave a comment.
Looking at the top answer from here: https://stackoverflow.com/questions/15959534/python-visibility-of-global-variables-in-imported-modules, I wonder if PyCharm is effectively doing a "from <module> import *" when you "run" it? It would explain the behaviour I'm seeing. I noted that just pasting the module into the console made it behave exactly like IDLE, also if I import the module and reference the global variable with the module name it also works correctly.
Could this be a configurable thing? If not, ought it to be?
Sorry - need to revise what I'm saying above: obviously PyCharm isn't executing a `from <module> import *`, because it is correctly executing the `if __name__ == '__main__'` block. However, it's as though, once the module has finished executing and returns control to the console, at that point the global variable is copied as a snapshot, as though a `from <module> import *` had been run. This is different from what happens when you "run a module" in IDLE, and different from what happens if you paste the code into the Python Console and execute it that way.
Hi Nick! Thank you for an interesting case! PyCharm uses execfile under the hood for Run with Python Console option. It looks like we're messing with global and local variables in an incorrect way. I created a ticket in our bug tracker to investigate the problem: PY-30940. Please feel free to comment there.