Jump to content

[python] how do i create a function that only runs 1 time?

Herr.Hoefkens

okay i have a quite large project , and when profiling it i noticed that it was losing allot of timee  running a certain function , which in my understanding should have only been ran 1 time for each time the parent got called , the result of that function is needed many times within the parent function. ive asked around but ... or im missing something really simple here (wich is also possible) . ive extracted the code from the project and in the mean time simplified the situation a dozen times but the result remains the same 😞

this is currently the most simplified version i have :

def rndfn():
	def subfn(d={}):		 			# mutable kwarg should persist during the run of its parent
		def runonce():	print('i ran');	return 'done'
		#if not d:	d=runonce() 			# should print i ran and store done in d
		#else:	d=d 					# if d exists (and thus == done) d should be just d (==done)
		d= d or runonce() 				# short hand for the two (commented) lines above
		return d
	test1=subfn() 						# this should cause runonce to run and set d to done
	test2=subfn() 						# this should see that d already ran and just get the value stored in d
	return test2						# should return done
print(rndfn())

wich yields the result :

i ran
i ran
done

while i hoped / expected to see i ran only once...

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

You are looking for the singleton pattern. I don't recall how to write it in Python as i haven't touch this old language in 25 years.

Link to comment
Share on other sites

Link to post
Share on other sites

If you need the result of a method multiple times but you only want to run the method once, implement some form of caching and/or lazy initialization.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

Did Run = false

 

Def function name :

if did run:

return

 

Global did Run = true

Did Run = false



Def function name :
  if did run:
    return

  global did Run = true 
  
  #more code

 

I don't recall exactly how python works but this is A solution... Maybe not the best solution. 

Link to comment
Share on other sites

Link to post
Share on other sites

Use a class. Define a class method that runs the function the first time you call it and after that it just returns the saved result. If the answer remains the same through the application, pass the variable along.

Link to comment
Share on other sites

Link to post
Share on other sites

its not a method its a function 😉 (i avoid making classes , makes for easier programming)

and imho , the name singleton, is an oxymoron 🙂

class , factory for  instances (objects), then a  singleton , one and only one instance of the class must exist , , nowhere in the real world does a factory exist that makes one offs 🙂

but anyway.

 

im currently solving it using a clojure, but the reason why the example i gave doesnt work as expected still baffles me.

def ArgKwargs(defaults,**k):
	args= defaults()|k			# everything in defaults gets ran/set  , and updated with the values of k
	def argkwargs(a):			# will remember the scope it was created inreturn the 
		return args[a] 			# returns the final values , and throws an error if someting is asked for that is nonexistant 
	return argkwargs			# (args.get() would return None and cause debuggin poblems later on so failure here is preffered

def bigfn(**k):
	def defaults():
		d	=	{
			'...':'...'
		}
		return d
	Arg = gnr.ArgKwargs(defaults,**k) 	# d gets passed in wrapped in a function, returs a function so every value can be gotten by calling
    									# Arg('value')

 

Link to comment
Share on other sites

Link to post
Share on other sites

11 hours ago, Herr.Hoefkens said:

(i avoid making classes , makes for easier programming)

I disagree but it's your project 😛 With global functions instead of classes, scope is much harder to control...

 

Quote

You are looking for the singleton pattern

Singletons are bad and considered an anti-pattern nowdays.

 

Quote

but the reason why the example i gave doesn't work as expected still baffles me.

Try to replace test2=subfn() with test2=subfn(test1)  and it should work, no?

 

Link to comment
Share on other sites

Link to post
Share on other sites

11 hours ago, AlexQC said:

Singletons are bad and considered an anti-pattern nowdays.

Singletons are good, just over used. 

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

3 hours ago, fpo said:

Singletons are good, just over used. 

 

 

Like anything it really depends, but it's largely considered an anti-pattern.

Link to comment
Share on other sites

Link to post
Share on other sites

just call the function once and it will only run once

 

or use the hasattr function:

def funcWithState():
  if not hasattr(funcWithState, "cache"):
     print("this part only runs once")
     funcWithState.cache = "stuff"  #put sutff into the cace during first call
  
  return funcWithState.cache;

print(funcWithState())
print(funcWithState())
print(funcWithState())

Edit: this is the result:

this part only runs once
stuff
stuff
stuff

ಠ_ಠ

Link to comment
Share on other sites

Link to post
Share on other sites

On 11/16/2022 at 12:50 AM, FFY00 said:

If the result is constant given the arguments, or if the function doesn't have arguments at all, just use `lru_cache`.

 

https://docs.python.org/3/library/functools.html#functools.lru_cache

thanks i did not know about this one

On 11/15/2022 at 11:02 PM, shadow_ray said:

just call the function once and it will only run once

 

or use the hasattr function:

def funcWithState():
  if not hasattr(funcWithState, "cache"):
     print("this part only runs once")
     funcWithState.cache = "stuff"  #put sutff into the cace during first call
  
  return funcWithState.cache;

print(funcWithState())
print(funcWithState())
print(funcWithState())

Edit: this is the result:

this part only runs once
stuff
stuff
stuff

neither about this.

at first glance i figured they werent usable in my case but defenetly usable in many other parts of the project, but after pondering on it for a while they are verry usable in this situation. the wrapping function does have changing arguments but the runonce does not .  and its not so much any iobound that makes it pretty slow ,and memory hungry its the fact that it has to switch between native arrays and python arrays , allot and also loop over them quite a bit , and that allot of times just as is  without running it multiple times needlessly causing the app to almost require a loading screen.

On 11/15/2022 at 6:17 AM, AlexQC said:

I disagree but it's your project 😛 With global functions instead of classes, scope is much harder to control...

 

Singletons are bad and considered an anti-pattern nowdays.

 

Try to replace test2=subfn() with test2=subfn(test1)  and it should work, no?

 

scope is harder to control only and only if you allow it to 😜 if you make sure any global(used in multiple modulles i assume) function is a pure function the scope is contained within the calling function... not using classes (when not absolutely needed, and so far only place i found that to be true is for packing stuff that is user oriented , as an example when making an html parser , having classes that match the css classes , and html tags is pretty much the only sensible way to go about it  at the first level of abstraction, its not absolutely unavoidable ofc but one would be shooting oneself in his foot if one were to attempt , abstracting the html stuff and deconstructing it in the same level, same goes for all ml and markdown kind of stuff ofc )

 

one major advantage of avoiding classes this way is , that hiearchy doesent need to be enforced , as inheritance is nonexistent .. another is that adhering to the col 80 rule becomes much easier as you dont tend to have   abstractfactoryclass.redundandnamesubclass.moreredundantverbtonouner.helper.method() so much 🙂

i always thend to smile when i see one of them 😛 thinking yeah yet another multibutsupporter here 😄The world seen by an "Object-Oriented" programmer. : r/ProgrammerHumor

on a side note the last comment here is highly language dependant , since python does a weird thing where functions of a modulle are accessible in the same way methods of a function are accessible , there is no way to tell if name.fn is actually a class with method call or a module.function call , just by that line of code , (modulles need to be imported and classes isntansiated ofc) but you get the point i hope. so a module really looks like some sort of class but isnt as there are no instnces of it and you cant pass any arguments to it . so modules seem to exist halfway between the class and function not being one or thee other , in my opinion really alligning a modulle with either being and behaving completely like a class or extending functions to behave like a module (and modules to accept arguments when called from within python and allowing for return values) would have been more consistent and the interpreter could determen if a module is called as __main_ and default return value's to stdout (making it nice and posix like) and passing any arguments or options that werre passed allong with it to sys.argv (as is the case ) but also accepting a def main(arg, kwarg): wher arg and kwarg are mod.py arg --kwarg value

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×