By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,091 Members | 1,546 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,091 IT Pros & Developers. It's quick & easy.

Function to execute only once

P: n/a
Hi if I have a function called
tmp=0
def execute():
tmp = tmp+1
return tmp

also I have
def func1():
execute()
....
and
def func2():
execute()
....

now I want execute() function to get executed only once. That is the
first time it is accessed.
so taht when funcc2 access the execute fn it should have same values as
when it is called from func1.

Oct 14 '05 #1
Share this Question
Share on Google+
9 Replies


P: n/a
If I understand you correctly, you want `tmp' to be global...

If so, declare it as so in execute ->

def execute():
global tmp
tmp = tmp+1
return tmp

Otherwise, what happens is that you declare a variable local to
execute, that is named tmp. When the assignment occurs it uses the
global value of `tmp', which is 0, and adds it to the *local* tmp.

I hope that is not too confusing.

jw

On 14 Oct 2005 12:11:58 -0700, PyPK <su*******@gmail.com> wrote:
Hi if I have a function called
tmp=0
def execute():
tmp = tmp+1
return tmp

also I have
def func1():
execute()
....
and
def func2():
execute()
....

now I want execute() function to get executed only once. That is the
first time it is accessed.
so taht when funcc2 access the execute fn it should have same values as
when it is called from func1.

--
http://mail.python.org/mailman/listinfo/python-list

Oct 14 '05 #2

P: n/a
"PyPK" <su*******@gmail.com> writes:
now I want execute() function to get executed only once. That is the
first time it is accessed.
so taht when funcc2 access the execute fn it should have same values as
when it is called from func1.


There's nothing built into Python for that. You have to program the
function to remember whether it's already been called. It sounds like
you're trying to avoid performing some side effect more than once.

Anyway, there's multiple ways you can do it. The conceptually
simplest is probably just use an attribute on the function:

tmp = 0 # you want to modify this as a side effect
def execute():
global tmp
if not execute.already_called:
tmp += 1
execute.already_called = True
return tmp
execute.already_called = False

Other ways include using a class instance, using an iterator, etc.

Generally too, you might find it cleaner to avoid having side effects
like that. Instead, put tmp itself inside a class instance:

class Memo:
def __init__(self):
self.value = 0 # any side effects operate on this
self.already_called = False

def __call__(self):
if not self.already_called:
self.already_called = True
self.value += 1
return self.value

execute = Memo()

Now you don't have global state cluttering things up, you can make
multiple instances easily, etc.
Oct 14 '05 #3

P: n/a
PyPK wrote:
now I want execute() function to get executed only once. That is the
first time it is accessed.


How about just calculating the value at import time?
--
Benji York
Oct 14 '05 #4

P: n/a
I've been seeing alot about decorators and closures lately and my
initial thought was that this would be a good place to use them instead
of wrapping it around a class. That was my initial thought :) What I
came up with was this:
def execute_once(fn):
result = None
def executor(*args, **kwargs):
if not result:
result = fn(*args, **kwargs)
return result
return executor

@execute_once
def execute(tmp):
tmp = tmp+1
return tmp

def func1(tmp):
execute(tmp)

def func2(tmp):
execute(tmp)

tmp=0
print 'init tmp:', tmp
func1(tmp)
print 'ran func1 tmp:', tmp
func2(tmp)
print 'ran func2 tmp:', tmp

It gives the following error:
init tmp: 0
Traceback (most recent call last):
File "C:\Download\test.py", line 26, in ?
func1(tmp)
File "C:\Download\test.py", line 19, in func1
execute(tmp)
File "C:\Download\test.py", line 5, in executor
if not result:
UnboundLocalError: local variable 'result' referenced before assignment

Makes sense to me, except I expected some closure 'magic'. I thought
that when I wrapped executor() inside execute_once() the name result
would be available to executor(). What am I missing here (I expect the
answer to be 'alot') but is this type of solution valid for this
problem?

Oct 14 '05 #5

P: n/a
The problem seemed to be because I was rebinding result inside
executor. Can someone explain why it works below but not in the first
one?

Also why is it if I set tmp as a global and don't pass it as a
paremeter to the various functions as per the OP that I get an
"UnboundLocalError: local variable 'tmp' referenced before assignment"?

def execute_once(fn):
print "in execute_once"
result = {}
def executor(*args, **kwargs):
if fn not in result:
result[fn] = fn(*args, **kwargs)
return result[fn]
return executor

@execute_once
def execute(tmp):
print "in execute"
tmp = tmp+1
return tmp

def func1(tmp):
return execute(tmp)

def func2(tmp):
return execute(tmp)

tmp = 0
print 'init tmp:', tmp
tmp = func1(tmp)
print 'ran func1 tmp:', tmp
tmp = func2(tmp)
print 'ran func2 tmp:', tmp
tmp = func1(tmp)
print 'ran func1 tmp:', tmp

OUTPUT:
in execute_once
init tmp: 0
in execute
ran func1 tmp: 1
ran func2 tmp: 1
ran func1 tmp: 1

Oct 14 '05 #6

P: n/a
"snoe" <ca*********@gmail.com> writes:
Also why is it if I set tmp as a global and don't pass it as a
paremeter to the various functions as per the OP that I get an
"UnboundLocalError: local variable 'tmp' referenced before assignment"?


If you don't declare it as a global, and if you try to assign a value
to it, then Python thinks it's a local. If you only refer to it and
never assign it, Python decides it's global. Python is weird that
way. One consequence is that if it's local to some outer scope, then
it's neither global nor local to your function, so there's no way to
assign to it.

I think Pythonic style is to not do complex things with closures,
but to use class instances instead.
Oct 14 '05 #7

P: n/a
"snoe" <ca*********@gmail.com> wrote:
I've been seeing alot about decorators and closures lately and my
initial thought was that this would be a good place to use them instead
of wrapping it around a class. That was my initial thought :) What I
came up with was this:


Apparently you're not the first to think of it:
http://aspn.activestate.com/ASPN/Coo.../Recipe/425445.

George
Oct 14 '05 #8

P: n/a
On 14 Oct 2005 12:11:58 -0700, "PyPK" <su*******@gmail.com> wrote:
Hi if I have a function called
tmp=0
def execute():
tmp = tmp+1
return tmp

also I have
def func1():
execute()
....
and
def func2():
execute()
....

now I want execute() function to get executed only once. That is the
first time it is accessed.
so taht when funcc2 access the execute fn it should have same values as
when it is called from func1.


You could have the execute function replace itself with a function
that returns the first result from there on, e.g., (assuming you want
the global tmp incremented once (which has bad code smell, but can be expedient ;-)):
tmp = 0
def execute(): ... global tmp, execute
... tmp = cellvar = tmp + 1
... def execute():
... return cellvar
... return tmp
... def func1(): ... return execute() # so we can see it
... def func2(): ... return execute() # so we can see it
... func1() 1 tmp 1 func2() 1 tmp 1 execute() 1 execute <function execute at 0x02EF702C> import dis
dis.dis(execute)

5 0 LOAD_DEREF 0 (cellvar)
3 RETURN_VALUE

But if you want to call the _same_ "execute" callable that remembers that
it's been called and does what you want, you need a callable that can
remember state one way or another. A callable could be a function with
a mutable closure variable or possibly a function attribute as shown in
other posts in the thread, or maybe a class bound method or class method,
or even an abused metaclass or decorator, but I don't really understand
what you're trying to do, so no approach is likely to hit the mark very well
unless you show more of your cards ;-)

Regards,
Bengt Richter
Oct 16 '05 #9

P: n/a
Bengt Richter wrote:
<snip>
>>> tmp = 0
>>> def execute():

... global tmp, execute
... tmp = cellvar = tmp + 1
... def execute():
... return cellvar
... return tmp

<snip>

On man did this put my head into a spin :P

--
Lasse Vågsæther Karlsen
http://usinglvkblog.blogspot.com/
mailto:la***@vkarlsen.no
PGP KeyID: 0x2A42A1C2
Oct 16 '05 #10

This discussion thread is closed

Replies have been disabled for this discussion.