Page 1 of 1

Structured prog & global variables

Posted: Tue May 07, 2019 6:28 am
by Roffey
In my ignorance I don't know if this is hardware specific or not. Using an ESP32 spiram.
I have a main program which is getting a little messy, so I have started to use extra files which have function def's in. In the main program I 'import from' so I can use them.
All goes well until I want to manipulate variables which have been declared in the main file. All that I have read indicates that if I declare the variables as 'global' within the external function, before I use them, then they can be accessed.
Well, whatever I do, I get errors thrown up, in that the variable is not recognised.
I would appreciate any guidance here ….. I have done my best in terms of searching … but to no avail.

As a second related question, I have also got a socket (udp) set up in the main program, which retrieves sent data. This all works fine.
In the same 'external' function with the global variable issue, I would like to refer to the socket for sending data out. This also fails.

All works well if I place the function back in the main section, but it would be nice to structure the program in a more orderly fashion.

Thanks for any help.
D.R.

Re: Structured prog & global variables

Posted: Tue May 07, 2019 10:03 am
by OutoftheBOTS_
It is best if possible to avoid global variables where possible.

The cleanest way to have many functions access a common variable is to use a class and then use the prefix self. before any variables that you want to be accessible from all the other functions/methods of the class.

see https://www.tutorialspoint.com/python/p ... bjects.htm

Re: Structured prog & global variables

Posted: Tue May 07, 2019 11:06 am
by Roffey
Thank you for that …. still learning.... only a few years to go!
Off to do some reading then.

Thanks again

Re: Structured prog & global variables

Posted: Thu May 09, 2019 5:47 am
by pythoncoder
The advice about avoiding globals is undoubtedly correct. Access is relatively slow. But there are other reasons rooted in general programming practice which you can research online.

It's worth understanding Python's scoping rules. If a module has a global name (whether for data or for an object such as a function) the name's visibility to other modules depends on how the module is imported.

my_module:

Code: Select all

bar = 42
def foo():
    return bar

Code: Select all

import my_module
my_module.foo()  # Access by prepending the module name
my_module.bar = 99
print(my_module.foo())  # 99

Code: Select all

from my_module import foo
foo()
bar = 99 # Will create a new variable local to the current module
print(foo())  # Will return 42
The need for a global statement arises if a function needs to modify a global variable. Consider the following

Code: Select all

bar = 42
def foo():
    global bar
    bar = 99
Without the global statement foo() would create a local variable bar and set that to 99 leaving the global bar unchanged: in other words foo() would do nothing useful. For some reason when I was learning Python this took me a while to grasp.

There is an option to import all exposed names from a module with

Code: Select all

from some_module import *
This should be used with care as it can populate your local namespace with unexpected names and can be a source of evil bugs (say if the author has redefined a Python built-in function). Only use if you understand the module you're importing.

Re: Structured prog & global variables

Posted: Thu May 09, 2019 7:31 am
by Roffey
Thanks for taking the time ….. these snippets really help get a better understanding ….

Re: Structured prog & global variables

Posted: Thu May 09, 2019 9:15 am
by JumpZero
Hello,
We know that using global variables isn't a good practice. But it's sometimes convenient and Python permits it.

However I was recently surprised to find that global variables are global to a module not across all modules. Reading the doc teachs me this is normal behavior. So that's ok when you know it, and one more reason to avoid "global" or at least to be (very) careful.

Exemple tested on Python3 on PC and microPython 1.10 on ESP32

Code: Select all

>>> def foo():
...     global bar
...     bar = bar + 1
...     return bar
...     
...     
... 
>>> bar = 5
>>> foo()
6
>>>  
Now we define the same function but in a module:
my_module.py :

Code: Select all

def foo():
    global bar
    bar = bar + 1
    return bar

Code: Select all

>>> import my_module
>>> bar = 5
>>> my_module.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my_module.py", line 3, in foo
NameError: name 'bar' isn't defined
>>>  

Re: Structured prog & global variables

Posted: Thu May 09, 2019 4:22 pm
by pythoncoder
Actually this is a strength of Python. If you issue

Code: Select all

import my_module
you have a guarantee that the only name added to your namespace is my_module: names within the module a guaranteed not to conflict with your own because you have to prepend them with the module name:

Code: Select all

import my_module
x = my_module.foo()
Likewise if you issue

Code: Select all

from my_module import foo, bar
you know exactly which names you've added. Issuing

Code: Select all

from my_module import *
will populate your namespace with an arbitrary assortment of names. This can have unforeseen consequences. It has its uses, but you need to study the module code.

This is the sort of chaos which your truly global variables might unleash ;)

Re: Structured prog & global variables

Posted: Thu May 09, 2019 4:34 pm
by dhylands
JumpZero wrote:
Thu May 09, 2019 9:15 am
Now we define the same function but in a module:
my_module.py :

Code: Select all

def foo():
    global bar
    bar = bar + 1
    return bar

Code: Select all

>>> import my_module
>>> bar = 5
>>> my_module.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my_module.py", line 3, in foo
NameError: name 'bar' isn't defined
>>>  
Your my_module.py file should rather contain:

Code: Select all

bar = 0
def foo():
    global bar
    bar = bar + 1
    return bar
and then if you wanted to change the global, you'd do:

Code: Select all

>>> import my_module
>>> my_module.bar = 5
>>> my_module.foo()
6

Re: Structured prog & global variables

Posted: Fri May 10, 2019 3:50 pm
by JumpZero
Hi!

Actually very interesting discussion.

@dhylands you are right the proper way to access the module global variable "bar" is:
"my_module.bar" this avoids confusion, keeping in mind that the main programme global variable "bar" is another variable.

@pythoncoder Yes this is a Python strength: the guarantee of names being uniques in user's namespace when you prepend them with module name. And thanks to pointing out the risks of using

Code: Select all

from module import * 
I didn't realize that. Better be careful and use the full name with module name prepending.

And now for the fun: the unleashed sort of chaos ;-)

Code: Select all

jumpzero@penguin:~$ cat my_module.py 
bar = 0
def foo():
    global bar
    bar = bar+1
    return bar
jumpzero@penguin:~$ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39) 
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> bar = 3
>>> bar
3
>>> from my_module import *
>>> bar
0
>>> foo()
1
>>> bar = 7
>>> bar
7
>>> foo()
2
>>> bar
7
>>> foo()
3
>>> 
:o :shock: :D