问题
I want to write a function which behaves exactly similar to the given function, except that it prints the time consumed in executing it. Just like this:
>>> fib = profile(fib)
>>> fib(20)
time taken: 0.1 sec
10946
This is my code,and it will print message in each function call.
import time
def profile(f):
def g(x):
start_time = time.clock()
value = f(x)
end_time = time.clock()
print('time taken: {time}'.format(time=end_time-start_time))
return value
return g
@profile
def fib(n):
if n is 0 or n is 1:
return 1
else:
return fib(n-1) + fib(n-2)
My code above will print a message 'taken time:...' for each fib(n-1).So there will be many many messages 'taken time:...'. Can I find a way to just print executing time of fib(20) not every executing time of fib(n-1)?
回答1:
I'm assuming your question is "how do I write profile
so that it only prints one message even when I decorate a function that can call itself?"
You could keep track of which functions are currently being timed. That way, if a function calls itself, you know that you're already timing it further up the stack, and don't need to do anything for the second instance.
def profile(f, currently_evaluating=set()):
#`currently_evaluating` will persist across all decorated functions, due to "mutable default argument" behavior.
#see also http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument
def g(x):
#don't bother timing it if we're already doing so
if f in currently_evaluating:
return f(x)
else:
start_time = time.clock()
currently_evaluating.add(f)
try:
value = f(x)
finally:
currently_evaluating.remove(f)
end_time = time.clock()
print('time taken: {time}'.format(time=end_time-start_time))
return value
return g
If you're using 3.X, you can cut down on mutable default argument weirdness by using the nonlocal
keyword.
def profile(f):
is_evaluating = False
def g(x):
nonlocal is_evaluating
if is_evaluating:
return f(x)
else:
start_time = time.clock()
is_evaluating = True
try:
value = f(x)
finally:
is_evaluating = False
end_time = time.clock()
print('time taken: {time}'.format(time=end_time-start_time))
return value
return g
回答2:
You can use a class as your profiler:
import time
class ProfileRecursiveFib(object):
def __call__(self, func):
self.start_time = time.clock()
def g(x):
return func(x)
self.end_time = time.clock()
print('time taken: {0}'.format(self.end_time - self.start_time))
return g
profile = ProfileRecursiveFib()
@profile
def fib(n):
if n is 0 or n is 1:
return 1
else:
return fib(n-1) + fib(n-2)
result = fib(20)
print(result)
This prints time (only once) and result:
time taken: 9.056212818586247e-07
10946
回答3:
I understood the answer you expected. you have tiny mistakes in your code, just go through the below code,
import time
def profile(f):
start_time=time.time()
def g(x):
value = f(x)
return value
print("time taken : %f seconds"%(time.time()-start_time))
return g
def fib(n):
if n is 0 or n is 1:
return 1
else:
return fib(n-1) + fib(n-2)
x = profile(fib)
print(x(20))
来源:https://stackoverflow.com/questions/29560643/python-counting-executing-time-of-a-recursion-function-with-decorator