User avatar
SavagePi
Posts: 42
Joined: Mon Mar 31, 2014 7:34 pm
Location: Staffordshire, England

Retaining variables within functions

Sat Jul 05, 2014 1:04 pm

My apologies if this question has already been answered elsewhere, but searching the forum doesn't seem to come up with anything.
As a newbie to Python, I was wondering if it's possible to retain variable values within functions, rather than getting the 'UnboundLocalError: local variable 'x' referenced before assignment' error.
It seems that once a function has completed, all of the variable values used within that function are simply 'discarded' (not remembered when the function is called again).
Here's my (rather simplified) example;

Code: Select all

# the function where I want to retain the value of 'x' within the function
def any_function(value,count):
    if count == 1:
        x = 0
    x = x + 1
    z = value [x]
    # do something with 'z' here...
    return()
#
# Main program...
y = 0
number = [1, 20, 6, 55, 42, 100]
#
for w in range (6):
    # do something here...
    y = y + 1
    any_function(number,y)
# carry on doing something else here...
This works fine when 'any_function' is called for the first time (obviously), but errors with subsequent calls. Within the function, I only want 'x' to be zero if the second parameter I pass (count) is '1'. Otherwise, I want 'x' to keep increasing. Is there a simple way of implimenting this?
Any help will be gratefully welcome.
Electronics... It's what I do!

gkreidl
Posts: 5953
Joined: Thu Jan 26, 2012 1:07 pm
Location: Germany

Re: Retaining variables within functions

Sat Jul 05, 2014 1:16 pm

Put "x = 0" on top of your script (making it a global variable of the module)
start your function with
global x

Then your changes to x will be written to the global variable x
Minimal Kiosk Browser (kweb)
Slim, fast webkit browser with support for audio+video+playlists+youtube+pdf+download
Optional fullscreen kiosk mode and command interface for embedded applications
Includes omxplayerGUI, an X front end for omxplayer

User avatar
SavagePi
Posts: 42
Joined: Mon Mar 31, 2014 7:34 pm
Location: Staffordshire, England

Re: Retaining variables within functions

Sat Jul 05, 2014 1:42 pm

gkreidl wrote:Put "x = 0" on top of your script (making it a global variable of the module)
start your function with
global x

Then your changes to x will be written to the global variable x
I was thinking of doing that, gkreidl, and it is an option, I agree. But I'm not fond of globalising 'variables' and changing them within functions. I prefer to keep function variables exclusive. It's just a shame they seem to be 'forgotten' once the function ends!
Electronics... It's what I do!

User avatar
joan
Posts: 14017
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Retaining variables within functions

Sat Jul 05, 2014 1:51 pm

SavagePi wrote:
gkreidl wrote:Put "x = 0" on top of your script (making it a global variable of the module)
start your function with
global x

Then your changes to x will be written to the global variable x
I was thinking of doing that, gkreidl, and it is an option, I agree. But I'm not fond of globalising 'variables' and changing them within functions. I prefer to keep function variables exclusive. It's just a shame they seem to be 'forgotten' once the function ends!
Once they are gone out of scope they are lost.

Python doesn't have the concept of function static variables which retain their value over function calls.

I'd guess the proper (in Python terms) thing to do is turn your functionality into a class.

User avatar
PeterO
Posts: 4727
Joined: Sun Jul 22, 2012 4:14 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 2:22 pm

This is a weak part of the language :-(
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

gkreidl
Posts: 5953
Joined: Thu Jan 26, 2012 1:07 pm
Location: Germany

Re: Retaining variables within functions

Sat Jul 05, 2014 2:44 pm

PeterO wrote:This is a weak part of the language :-(
PeterO
No, hiding a global variable (and calling it "static") inside a function is just an eyewash.
Minimal Kiosk Browser (kweb)
Slim, fast webkit browser with support for audio+video+playlists+youtube+pdf+download
Optional fullscreen kiosk mode and command interface for embedded applications
Includes omxplayerGUI, an X front end for omxplayer

User avatar
PeterO
Posts: 4727
Joined: Sun Jul 22, 2012 4:14 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 2:56 pm

gkreidl wrote:
PeterO wrote:This is a weak part of the language :-(
PeterO
No, hiding a global variable (and calling it "static") inside a function is just an eyewash.
I have no idea what you mean by "eyewash" in this context but you seem to not understand the meaning of "static" (at least not in the way it is used in "C").

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
SavagePi
Posts: 42
Joined: Mon Mar 31, 2014 7:34 pm
Location: Staffordshire, England

Re: Retaining variables within functions

Sat Jul 05, 2014 3:11 pm

PeterO wrote:
gkreidl wrote:
PeterO wrote:This is a weak part of the language :-(
PeterO
No, hiding a global variable (and calling it "static") inside a function is just an eyewash.
I have no idea what you mean by "eyewash" in this context but you seem to not understand the meaning of "static" (at least not in the way it is used in "C").

PeterO
I can sort of understand what gkreidl is talking about. There are no 'static' variables within functions once that function has finished. It also means you have to be careful when assigning variables outside the function. Using widespread globalisation means it can be difficult keeping track of some variables that are repeated program-wide.
Electronics... It's what I do!

User avatar
PeterO
Posts: 4727
Joined: Sun Jul 22, 2012 4:14 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 3:24 pm

SavagePi wrote:
I can sort of understand what gkreidl is talking about. There are no 'static' variables within functions once that function has finished. It also means you have to be careful when assigning variables outside the function. Using widespread globalisation means it can be difficult keeping track of some variables that are repeated program-wide.
No. that's the point I was making. These are weak parts of the language that mix up the concepts of global and static variables.
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
SavagePi
Posts: 42
Joined: Mon Mar 31, 2014 7:34 pm
Location: Staffordshire, England

Re: Retaining variables within functions

Sat Jul 05, 2014 6:35 pm

PeterO wrote:No. that's the point I was making. These are weak parts of the language that mix up the concepts of global and static variables.
PeterO
That's a valid point PeterO. I suppose the 'weak' part of the language is the way the Python interpreter stores (or doesn't store) variables. Since variables within functions are considered 'local' to that particular function, it's a pity they just get 'dumped' when the function ends. You'd expect them to continue to exist. :?
Electronics... It's what I do!

User avatar
PeterO
Posts: 4727
Joined: Sun Jul 22, 2012 4:14 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 6:49 pm

SavagePi wrote: That's a valid point PeterO. I suppose the 'weak' part of the language is the way the Python interpreter stores (or doesn't store) variables.
How the interpreter works is irrelevant. The language syntax takes a non obvious approach to scope, using the keyword global in a very non-intuative and inconsistent way. See if you can predict what this code will print....

Code: Select all

#!/usr/bin/python

y = 0
z = 0
numbers = {}

def testscope():
    global y
    x = 10
    print "x=",x,"y=",y
    y = y + 1
    z = 9
    numbers[1] = "one"

y = 5

testscope()

print "y=",y,"z=",z
print numbers

Don't get me wrong, I like programming in Python, and do it both for fun and professionally, http://www.raspberrypi.org/forums/viewt ... 63&t=80987
But its odd behaviour does cause headaches sometimes !
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
SavagePi
Posts: 42
Joined: Mon Mar 31, 2014 7:34 pm
Location: Staffordshire, England

Re: Retaining variables within functions

Sat Jul 05, 2014 7:55 pm

PeterO wrote:How the interpreter works is irrelevant. The language syntax takes a non obvious approach to scope, using the keyword global in a very non-intuative and inconsistent way. See if you can predict what this code will print....

Code: Select all

#!/usr/bin/python

y = 0
z = 0
numbers = {}

def testscope():
    global y
    x = 10
    print "x=",x,"y=",y
    y = y + 1
    z = 9
    numbers[1] = "one"

y = 5

testscope()

print "y=",y,"z=",z
print numbers

Don't get me wrong, I like programming in Python, and do it both for fun and professionally, http://www.raspberrypi.org/forums/viewt ... 63&t=80987
But its odd behaviour does cause headaches sometimes !
PeterO
You just knew I was going to 'cheat' and try the code out for myself, didn't you?
The 'y' and 'z' values are perfectly understandable (the function altered 'y' as a global variable, but wouldn't have any effect on the external 'z' variable, so that variable wouldn't be affected - I can understand that). But, I was very surprised that the function could add a value to the external 'numbers' array. How strange!
Now that was worth learning.
Thank you.
Electronics... It's what I do!

gordon77
Posts: 4003
Joined: Sun Aug 05, 2012 3:12 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 8:32 pm

Try this,

When calling the function use

Z = any_function(x,y)

And a the end if the function use

Return (z)

User avatar
PeterO
Posts: 4727
Joined: Sun Jul 22, 2012 4:14 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 8:57 pm

SavagePi wrote: You just knew I was going to 'cheat' and try the code out for myself, didn't you?
But of course ! :-)
The 'y' and 'z' values are perfectly understandable (the function altered 'y' as a global variable, but wouldn't have any effect on the external 'z' variable, so that variable wouldn't be affected - I can understand that). But, I was very surprised that the function could add a value to the external 'numbers' array. How strange!
Now that was worth learning.
Thank you.
Now you see what I mean... Variables with apparently the same scope behaving differently... Probably something to do with the dictionary being accessed via a reference but I've seen this inconsistent behaviour trip up some very experienced programmers when they first start writing Python code.
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
SavagePi
Posts: 42
Joined: Mon Mar 31, 2014 7:34 pm
Location: Staffordshire, England

Re: Retaining variables within functions

Sat Jul 05, 2014 9:02 pm

gordon77 wrote:Try this,

When calling the function use

Z = any_function(x,y)

And a the end if the function use

Return (z)
I've thought of using that method too, gordon77, but I wanted just the function alone to control the variable. Which I now understand cannot be done ;)
Nevertheless, thank you for the suggestion. It is appreciated.
Electronics... It's what I do!

User avatar
jojopi
Posts: 3078
Joined: Tue Oct 11, 2011 8:38 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 9:33 pm

Nobody has mentioned that functions can have attributes, which are static. I do not particularly like this approach, but I would rather use it than pollute the global namespace.

Code: Select all

def func(a):
  try:
    func.total += a
  except AttributeError:
    func.total = a
  return func.total

for i in range(6):
  print(i, func(i))
I suspect the most Pythonic approach is indeed a class. Personally I would be inclined to use a separate method for the reset operation, rather than a special argument to the main function.

User avatar
PeterO
Posts: 4727
Joined: Sun Jul 22, 2012 4:14 pm

Re: Retaining variables within functions

Sat Jul 05, 2014 10:17 pm

jojopi wrote:Nobody has mentioned that functions can have attributes, which are static. I do not particularly like this approach, but I would rather use it than pollute the global namespace.

Code: Select all

def func(a):
  try:
    func.total += a
  except AttributeError:
    func.total = a
  return func.total

for i in range(6):
  print(i, func(i))
Interesting.... But your use of the AttributeError exception seems to indicate there is no way to initialise an attribute ?
I suspect the most Pythonic approach is indeed a class. Personally I would be inclined to use a separate method for the reset operation, rather than a special argument to the main function.
ARGH !!! I have a major dislike of using classes where there is no underlying OO model to be implemented.... In most cases I've seen "OO for OO's sake" seems to make things more complex rather than simpler.

PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

KenT
Posts: 758
Joined: Tue Jan 24, 2012 9:30 am
Location: Hertfordshire, UK
Contact: Website

Re: Retaining variables within functions

Sun Jul 06, 2014 8:51 am

if you do not like classes you could put the global variables in modules, as described below, to limit their scope:

"Each module has its own private symbol table, which is used as the global symbol table by all functions defined in the module. Thus, the author of a module can use global variables in the module without worrying about accidental clashes with a user’s global variables. On the other hand, if you know what you are doing you can touch a module’s global variables with the same notation used to refer to its functions, modname.itemname."

Taken from https://docs.python.org/2/tutorial/modules.html Section 3.1

Each language seems to have different ways of implementing variables that have a long lifetime; a requirement which conflicts with modularity and structured programming. C has [edit] static, Fortran has common blocks, Algol 68 has Own and Python has global, classes and function attributes. C and Algol seem to do it best, perhaps because they are compiled rather than interpreted.
Last edited by KenT on Sun Jul 06, 2014 10:48 am, edited 1 time in total.
Pi Presents - A toolkit to produce multi-media interactive display applications for museums, visitor centres, and more
Download from http://pipresents.wordpress.com

Joe Schmoe
Posts: 4277
Joined: Sun Jan 15, 2012 1:11 pm

Re: Retaining variables within functions

Sun Jul 06, 2014 10:14 am

C has struct,
ITYM, static.
And some folks need to stop being fanboys and see the forest behind the trees.

(One of the best lines I've seen on this board lately)

KenT
Posts: 758
Joined: Tue Jan 24, 2012 9:30 am
Location: Hertfordshire, UK
Contact: Website

Re: Retaining variables within functions

Sun Jul 06, 2014 10:49 am

Joe Schmoe wrote:
C has struct,
ITYM, static.
Agreed, thanks for spot. It's edited.
Pi Presents - A toolkit to produce multi-media interactive display applications for museums, visitor centres, and more
Download from http://pipresents.wordpress.com

billio
Posts: 61
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: Retaining variables within functions

Mon Jul 07, 2014 9:03 pm

Returning to your original code I would like to add some points that might be useful though they don't directly answer your question:

Code: Select all

a = [1,2,3,4,5,6]
for i in a:
    # do something with i
allows you do what you show in the code, and doesn't risk an error when the value of y moves beyond the length of the list
but if you want to use the processing to use the position of i in the list, then :

Code: Select all

for i,val in enumerate(a):
     # do something with i and val
on the other hand you may want to use the function selecting the first, second, third etc. from the list as the function is called at several places in the software. In that case you need to make your list an iterator and call each element of the list using the next() function :

Code: Select all

b = iter(a)
# some code
c = next(b) # c will the first element of a
# some more code 
f = next(b) # f will be the next element of a
# and so on
# but really you should wrap these calls with try: and except: in order to catch the StopIteration error when the list runs out

# to return the item position
c = iter(list(enumerate(a)))
position,value = next(c)
The issue about the apparently different scope of integers and dictionaries is explained here : http://stackoverflow.com/questions/1306 ... difference. I admit it can be confusing initially because of the way Python handles mutable (a dictionary) and immutable variables (an integer).
Myself I find Python classes very useful regardless of whether the approach is Object Orientation or not.

User avatar
PeterO
Posts: 4727
Joined: Sun Jul 22, 2012 4:14 pm

Re: Retaining variables within functions

Mon Jul 07, 2014 9:13 pm

billio wrote: I admit it can be confusing initially because of the way Python handles mutable (a dictionary) and immutable variables (an integer).
Myself I find Python classes very useful regardless of whether the approach is Object Orientation or not.
The mutable vs immutable stuff is another bit of Python bizzarness.... Calling integers "immutable" seems to rely on some "python only" meaning of immutable.... Python seems to often go out of it's way to be different.
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
AndrewS
Posts: 3625
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
Contact: Website

Re: Retaining variables within functions

Mon Jul 07, 2014 10:44 pm

I agree with billo that it looks like you want to be using 'enumerate'.

But to answer the original question, you can do what you asked for (having a function 'remember' a variable without putting it in the global namespace) by using closures

Code: Select all

def outer_func(x):
    # the function where I want to retain the value of 'x' within the function
    def inner_func(value, count):
        if count == 1:
            x[0] = 0
        x[0] += 1
        z = value[x[0]]
        # do something with 'z' here...
        return ()
    return inner_func

any_function = outer_func([0])
#
# Main program...
y = 0
number = [1, 20, 6, 55, 42, 100]
#
for w in range (6):
    # do something here...
    y = y + 1
    any_function(number,y)
# carry on doing something else here...
Yes it looks a bit icky, but it is what you asked for ;-)
You need to access x as an array, because the closure variable is read-only if passed as a simple integer (for the same mutuable/immutable reasons already mentioned).
Python seems to often go out of it's way to be different.
Every language has it's quirks, part of learning a new language is discovering what those quirks are :lol:

gkreidl
Posts: 5953
Joined: Thu Jan 26, 2012 1:07 pm
Location: Germany

Re: Retaining variables within functions

Tue Jul 08, 2014 5:49 am

PeterO wrote: The mutable vs immutable stuff is another bit of Python bizzarness.... Calling integers "immutable" seems to rely on some "python only" meaning of immutable.... Python seems to often go out of it's way to be different.
PeterO
It depends, how variables are passed to functions; "immutable variables" are passed by value, "mutable variables" are passed by reference. In C string variables are passed as pointers (which has the same effect as passing mutable variables in Python, because you can modify the content of the string which resides outside of the function) while in Python strings are "primitives" (immutable) and not composite values (as lists and dictionaries).
Minimal Kiosk Browser (kweb)
Slim, fast webkit browser with support for audio+video+playlists+youtube+pdf+download
Optional fullscreen kiosk mode and command interface for embedded applications
Includes omxplayerGUI, an X front end for omxplayer

IanH2
Posts: 79
Joined: Tue Dec 18, 2012 10:17 am

Re: Retaining variables within functions

Wed Jul 09, 2014 9:36 am

SavagePi wrote:But I'm not fond of globalising 'variables' and changing them within functions. I prefer to keep function variables exclusive. It's just a shame they seem to be 'forgotten' once the function ends!
Your options are to either (a) use global variables, but isolate all the code which should have access to them in its own module (.py file), or (b) contain them in a class somehow.

If you have an objection to singleton objects (who doesn't?), you can very easily make the equivalent of C++ / Java's static variables and methods, using the @classmethod decorator - something like this:

Code: Select all

class AnyClass:
    _x = 0
    
    @classmethod
    def any_function(self,value,count):
        if count == 1:
            self._x = 0
        self._x += 1
        print "x was", self._x
        
# Usage...
AnyClass.any_function(12,1)
AnyClass.any_function(12,22)
AnyClass.any_function(12,33)
Think of AnyClass more of a namespace than a "type-of-object". You don't have to use a leading underscore for the variable name (as in _x), but it's a well-understood convention to indicate 'private' variables or methods.

In real life, you will often find a given 'global' variable will end up being shared between a small group of functions. For instance, in your example, the function has magic side-effects when count==1. It may be clearer to write it as:

Code: Select all

class AnyClass:
    _x = 0

    @classmethod
    def reset_count(self):
        self._x = 0
    
    @classmethod
    def any_function(self,value,count):
        self._x += 1
        print "x was", self._x

# Usage...
AnyClass.reset_count()
AnyClass.any_function(12,1)
AnyClass.any_function(12,2)
AnyClass.any_function(12,3)
-----
https://github.com/IanHarvey

Return to “Python”