How to obtain the cost time of each **def**? [duplicate] - python

This question already has answers here:
How do I profile a Python script?
(33 answers)
Closed 2 years ago.
I create a decorator to time the cost of every funcions :
def timmer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print('Func %s, run time: %s' % (func.__name__, stop_time - start_time))
return res
return wrapper
And use it every def , for example :
#timmer
def Test_func(*args,**kwargs):
return "hello !"
Then I can obtain the cost time of every func.
But if I do this , I have to use #timmer in every def .If this .py file has 100 defs , then I must use #timmer for 100 times.
How can I get the running time of each method conveniently ?

Create a master function which in turn calls any one of the 100 functions with the function name as a parameter
Use the decorator with this master function
Call the master function in a loop for all the 100 functions and save results in a list.append()

Related

How to cache a function using a decorator (Python)

I'm studying Python decorators, and I'm trying to write my own cache function (to better understand what caching is about).
This is what I tried:
def hash_table_fun(func):
hash_table = {}
def wrapper(*args):
if args not in hash_table:
hash_table[args] = func(*args)
return hash_table[args]
return wrapper
#hash_table_fun
def slow_function(a,b):
time.sleep(5)
return a + b
start_time = time.time()
print(slow_function(2,3))
print(f"Run time: {time.time() - start_time}")
The first time I call slow_function with the arguments 2 and 3, the function takes about 5s, as expected. But when I call slow_function a second time with the same arguments, it still takes 5s. What am I doing wrong?

Decorator strange behavior [duplicate]

This question already has answers here:
python decorator TypeError missing 1 required positional argument
(3 answers)
How to create a decorator that can be used either with or without parameters?
(16 answers)
Closed 2 years ago.
This is meant to calculate execution time and log / print it:
def timer(logger=None):
def decorator(func):
def wrapper(*args, **kwargs):
start_time = perf_counter()
result = func(*args, **kwargs)
total_time = perf_counter() - start_time
message = f'{func.__name__} Time: ' f'{total_time} seconds'
if logger is not None:
logger.info(message)
else:
print(message)
return result
return wrapper
return decorator
#timer
def decorated():
print("Running ...")
if __name__ == '__main__':
decorated()
I'm expecting this to print time, instead it complains about a missing argument:
TypeError: decorator() missing 1 required positional argument: 'func'
However, when I do:
#timer(None)
def decorated():
print("Running ...")
or:
#timer(logger=None)
def decorated():
print("Running ...")
It works! what is this nonsense?
Running ...
decorated Time: 2.3044999999999316e-05 seconds
Notes:
To those marking my question as a duplicate, can you explain why
other decorators work just fine?
In the example below, lru_cache accepts maxsize and typed parameters and works without explicit calls as well.
Example:
from functools import lru_cache
#lru_cache
def decorated():
print("Running ...")
Out:
Running ...

Python :Lambda Function Details in Decorator

Trying to add executing Process(Test,a,b) Name in the decoration where i am calculating Elapsed Time.Need Suggestions.
Final Expected Logs:
Process **a** elapsed time :3.8 || Rowcount=1833
Process **test** elapsed time :7.8 || Rowcount=1133
code
import time
from queries import a,b,test
def elapsedTimeTracker_decorator(func):
def wrapper():
start_time = time.time()
func()
print(test)
end_time = time.time()
elapsed_time = end_time - start_time
print('elapsed_time:'+ str(elapsed_time) +'||' + 'RowCount:' + str(cursor.rowcount))
return wrapper
print "Process a started"
elapsedTimeTracker_decorator(lambda: cursor.execute(a))()
print "Process Test started"
elapsedTimeTracker_decorator(lambda: cursor.execute(Test))()
print "Process b started"
elapsedTimeTracker_decorator(lambda: cursor.execute(b))()
a,b & test Consists of SQL Update Queries
test = """INSERT INTO users
select * from user_all where user_id=54549172 """
If you wish to print extra data for a decorated lambda that takes no arguments, then you have to pass it to your decorator:
def elapsedTimeTracker_decorator(func, test):
def wrapper():
start_time = time.time()
func()
print(f'Process {test} elapsed time: {time.time() - start_time} || Rowcount={cursor.rowcount}')
return wrapper
elapsedTimeTracker_decorator(lambda: cursor.execute(test), test)()
Other than that I have no idea where your test is supposed to comes from. Please elaborate with more details if that is not a suitable solution.
EDIT: Based on the latest information provided, it is clear that you do not need to use a lambda, nor a decorator with an inner wrapper. You could simply use a simple function that call the given one with the provided arguments and keywords that would take care of the call along with printing the execution time. For example:
from time import time as now
def time_call(func, *args, **kwargs):
cur = now()
func(*args, **kwargs)
print(
f'Executing {func.__qualname__}({repr(args)[1:-1]}, ' +
f'{"".join(f"{k}={v}" for k, v in kwargs.items())}) took ' +
f'{now() - cur} seconds.'
)
def test(foo, bar, baz):
pass
time_call(test, 'foo', 'bar', baz=None)
Which would prints something like:
Executing test('foo', 'bar', baz=None) took 0.0 seconds.

Decorated function returns "None"

I'm extremely new to python, and i just encountered decorators. I'm still kinda confused by them but i am learning
i was trying to make a decorator that tells me how much time my function took to finish, but apparently when i try to use it on a function that should return something, it just returns "None"
I've seen only a couple of questions talking about this problem but none of them actually helped
Here's my code
import time
def time_it(func): # Here i make a simple decorator function that should time my decorated function
def wrapper(*args, **kwargs):
t1 = time.time()
func(*args)
t2 = time.time()
total = t2 - t1
print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")
return wrapper
#time_it
def square(nums): # I make a function that squares every number in a list
new_list = []
for n in nums:
new_list.append(n ** 2)
return new_list
lis = [f for f in range(200000)] # i make a list with a range of 200000
print(square(lis))
sorry for any grammatical errors, i'm not a native english speaker
The problem is that your inner function return value isn't being returned. The change is noted below:
from functools import wraps
def time_it(func): # Here i make a simple decorator function that should time my decorated function
#wraps(func)
def wrapper(*args, **kwargs):
t1 = time.time()
## Note the change on this line -- I now store the return result from the called function
result = func(*args, **kwargs)
t2 = time.time()
total = t2 - t1
print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")
## And then explicitly return the result
return result
return wrapper
For the decorator, you need to remember that it's just a closure, with some fancy syntax. You still need to deal with the function return parameters yourself.
A couple of additions:
from functools import wraps and #wraps(func)
this will create wrap the inner function with some details that exist in the wrapping function. There's a small example in the python docs here:
https://docs.python.org/3/library/functools.html
The decorator replaces square with wrapper and wrapper does not return anything. It should return the value returned by the wrapped function.
This is the correct way to do it:
def time_it(func):
def wrapper(*args, **kwargs):
t1 = time.time()
try:
return func(*args, **kwargs)
finally:
t2 = time.time()
total = t2 - t1
print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")
return wrapper
I changed 3 things:
added return, so that the value is returned from decorated function
added **kwargs to func calls, because it may be needed if used differently
added try/finally block, so that the printout happens even in case of an exception, plus this makes it easier to return the value.
Your decorated function doesn't return anything explicitely - so, by default, it returns None.
You can capture the output before printing the time, and return at the end:
def time_it(func): # Here i make a simple decorator function that should time my decorated function
def wrapper(*args, **kwargs):
t1 = time.time()
out = func(*args)
t2 = time.time()
total = t2 - t1
print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete")
return out
return wrapper

How can I rate limit a function in Python 2.7 with a decorator? [duplicate]

This question already has answers here:
Read/Write Python Closures
(8 answers)
Closed 8 years ago.
I'm trying to write a decorator in Python to limit the number of times a function is called in an amount of time. I anticipate using it like this:
#ratelimit(seconds=15)
def foo():
print 'hello'
start = time.time()
while time.time() - start < 10:
foo()
> 'hello'
> 'hello'
So the decorated function can be called a maximum of once every seconds. In terms of implementing it I have this, but it doesn't work as I'm not sure the correct way to persist the last_call between subsequent calls:
import time
def ratelimit(seconds=10):
last_call = None # Never call decorated function
def decorator(func):
def wrapper(*args, **kwargs):
if last_call is None or time.time() - last_call > seconds:
result = func(*args, **kwargs)
last_call = time.time()
return result
return wraps(func)(wrapper)
return decorator
The code below worked fine for me in python 2.7.
import time
from functools import wraps
last_called = dict() # When last called, and with what result
def ratelimit(seconds=10, timer=time.time):
def decorator(func):
last_called[func] = None
#wraps(func)
def wrapper(*args, **kwargs):
now = timer()
call_data = last_called.get(func, None)
if call_data is None or now - call_data[0] >= seconds:
result = func(*args, **kwargs)
last_called[func] = (now, result)
else:
result = call_data[1] # Replay rate-limited result
return result
return wrapper
return decorator

Categories