noiftimer
69class Timer: 70 """Simple timer class that tracks total elapsed time 71 and average time between calls to `start()` and `stop()`.""" 72 73 def __init__( 74 self, averaging_window_length: int = 10, subsecond_resolution: bool = True 75 ): 76 """ 77 #### :params: 78 * `averaging_window_length`: Number of start/stop cycles to calculate the average elapsed time with. 79 80 * `subsecond_resolution`: Whether to print formatted time strings with subsecond resolution or not. 81 """ 82 self._start_time = time.time() 83 self._stop_time = self.start_time 84 self._elapsed = 0 85 self._average_elapsed = 0 86 self._history: deque[float] = deque([], averaging_window_length) 87 self._started: bool = False 88 self.subsecond_resolution = subsecond_resolution 89 self._pauser = _Pauser() 90 91 @property 92 def started(self) -> bool: 93 """Returns whether the timer has been started and is currently running.""" 94 return self._started 95 96 @property 97 def elapsed(self) -> float: 98 """Returns the currently elapsed time.""" 99 if self._started: 100 return time.time() - self._start_time - self._pauser.pause_total 101 else: 102 return self._elapsed 103 104 @property 105 def elapsed_str(self) -> str: 106 """Returns the currently elapsed time as a formatted string.""" 107 return self.format_time(self.elapsed, self.subsecond_resolution) 108 109 @property 110 def average_elapsed(self) -> float: 111 """Returns the average elapsed time.""" 112 return self._average_elapsed 113 114 @property 115 def average_elapsed_str(self) -> str: 116 """Returns the average elapsed time as a formatted string.""" 117 return self.format_time(self._average_elapsed, self.subsecond_resolution) 118 119 @property 120 def start_time(self) -> float: 121 """Returns the timestamp of the last call to `start()`.""" 122 return self._start_time 123 124 @property 125 def stop_time(self) -> float: 126 """Returns the timestamp of the last call to `stop()`.""" 127 return self._stop_time 128 129 @property 130 def history(self) -> deque[float]: 131 """Returns the history buffer for this timer.""" 132 return self._history 133 134 @property 135 def is_paused(self) -> bool: 136 return self._pauser.paused 137 138 def start(self: Self) -> Self: 139 """Start the timer. 140 141 Returns this Timer instance so timer start can be chained to Timer creation if desired. 142 143 >>> timer = Timer().start()""" 144 if not self.started: 145 self._start_time = time.time() 146 self._started = True 147 return self 148 149 def stop(self): 150 """Stop the timer. 151 152 Calculates elapsed time and average elapsed time.""" 153 if self.started: 154 self._stop_time = time.time() 155 self._started = False 156 self._elapsed = ( 157 self._stop_time - self._start_time - self._pauser.pause_total 158 ) 159 self._pauser.reset() 160 self._history.append(self._elapsed) 161 self._average_elapsed = sum(self._history) / (len(self._history)) 162 163 def reset(self): 164 """Calls stop() then start() for convenience.""" 165 self.stop() 166 self.start() 167 168 def pause(self): 169 """Pause the timer.""" 170 self._pauser.pause() 171 172 def unpause(self): 173 """Unpause the timer.""" 174 self._pauser.unpause() 175 176 @staticmethod 177 def format_time(num_seconds: float, subsecond_resolution: bool = False) -> str: 178 """Returns `num_seconds` as a string with units. 179 180 #### :params: 181 182 `subsecond_resolution`: Include milliseconds and microseconds with the output. 183 """ 184 microsecond = 0.000001 185 millisecond = 0.001 186 second = 1 187 seconds_per_minute = 60 188 seconds_per_hour = 3600 189 seconds_per_day = 86400 190 seconds_per_week = 604800 191 seconds_per_month = 2419200 192 seconds_per_year = 29030400 193 time_units = [ 194 (seconds_per_year, "y"), 195 (seconds_per_month, "mn"), 196 (seconds_per_week, "w"), 197 (seconds_per_day, "d"), 198 (seconds_per_hour, "h"), 199 (seconds_per_minute, "m"), 200 (second, "s"), 201 (millisecond, "ms"), 202 (microsecond, "us"), 203 ] 204 if not subsecond_resolution: 205 time_units = time_units[:-2] 206 time_string = "" 207 for time_unit in time_units: 208 unit_amount, num_seconds = divmod(num_seconds, time_unit[0]) 209 if unit_amount > 0: 210 time_string += f"{int(unit_amount)}{time_unit[1]} " 211 if time_string == "": 212 return f"<1{time_units[-1][1]}" 213 return time_string.strip() 214 215 @property 216 def stats(self) -> str: 217 """Returns a string stating the currently elapsed time and the average elapsed time.""" 218 return f"elapsed time: {self.elapsed_str}\naverage elapsed time: {self.average_elapsed_str}"
Simple timer class that tracks total elapsed time
and average time between calls to start() and stop().
73 def __init__( 74 self, averaging_window_length: int = 10, subsecond_resolution: bool = True 75 ): 76 """ 77 #### :params: 78 * `averaging_window_length`: Number of start/stop cycles to calculate the average elapsed time with. 79 80 * `subsecond_resolution`: Whether to print formatted time strings with subsecond resolution or not. 81 """ 82 self._start_time = time.time() 83 self._stop_time = self.start_time 84 self._elapsed = 0 85 self._average_elapsed = 0 86 self._history: deque[float] = deque([], averaging_window_length) 87 self._started: bool = False 88 self.subsecond_resolution = subsecond_resolution 89 self._pauser = _Pauser()
:params:
averaging_window_length: Number of start/stop cycles to calculate the average elapsed time with.subsecond_resolution: Whether to print formatted time strings with subsecond resolution or not.
138 def start(self: Self) -> Self: 139 """Start the timer. 140 141 Returns this Timer instance so timer start can be chained to Timer creation if desired. 142 143 >>> timer = Timer().start()""" 144 if not self.started: 145 self._start_time = time.time() 146 self._started = True 147 return self
Start the timer.
Returns this Timer instance so timer start can be chained to Timer creation if desired.
>>> timer = Timer().start()
149 def stop(self): 150 """Stop the timer. 151 152 Calculates elapsed time and average elapsed time.""" 153 if self.started: 154 self._stop_time = time.time() 155 self._started = False 156 self._elapsed = ( 157 self._stop_time - self._start_time - self._pauser.pause_total 158 ) 159 self._pauser.reset() 160 self._history.append(self._elapsed) 161 self._average_elapsed = sum(self._history) / (len(self._history))
Stop the timer.
Calculates elapsed time and average elapsed time.
163 def reset(self): 164 """Calls stop() then start() for convenience.""" 165 self.stop() 166 self.start()
Calls stop() then start() for convenience.
176 @staticmethod 177 def format_time(num_seconds: float, subsecond_resolution: bool = False) -> str: 178 """Returns `num_seconds` as a string with units. 179 180 #### :params: 181 182 `subsecond_resolution`: Include milliseconds and microseconds with the output. 183 """ 184 microsecond = 0.000001 185 millisecond = 0.001 186 second = 1 187 seconds_per_minute = 60 188 seconds_per_hour = 3600 189 seconds_per_day = 86400 190 seconds_per_week = 604800 191 seconds_per_month = 2419200 192 seconds_per_year = 29030400 193 time_units = [ 194 (seconds_per_year, "y"), 195 (seconds_per_month, "mn"), 196 (seconds_per_week, "w"), 197 (seconds_per_day, "d"), 198 (seconds_per_hour, "h"), 199 (seconds_per_minute, "m"), 200 (second, "s"), 201 (millisecond, "ms"), 202 (microsecond, "us"), 203 ] 204 if not subsecond_resolution: 205 time_units = time_units[:-2] 206 time_string = "" 207 for time_unit in time_units: 208 unit_amount, num_seconds = divmod(num_seconds, time_unit[0]) 209 if unit_amount > 0: 210 time_string += f"{int(unit_amount)}{time_unit[1]} " 211 if time_string == "": 212 return f"<1{time_units[-1][1]}" 213 return time_string.strip()
Returns num_seconds as a string with units.
:params:
subsecond_resolution: Include milliseconds and microseconds with the output.
10def time_it(loops: int = 1) -> Callable[..., Any]: 11 """Decorator to time function execution time and print the results. 12 13 #### :params: 14 15 `loops`: How many times to execute the decorated function, 16 starting and stopping the timer before and after each loop.""" 17 18 def decorator(func: Callable[..., Any]) -> Callable[..., Any]: 19 @wraps(func) 20 def wrapper(*args: Any, **kwargs: Any) -> Any: 21 timer = Timer(loops) 22 result = None 23 for _ in range(loops): 24 timer.start() 25 result = func(*args, **kwargs) 26 timer.stop() 27 print( 28 f"{func.__name__} {'average ' if loops > 1 else ''}execution time: {timer.average_elapsed_str}" 29 ) 30 return result 31 32 return wrapper 33 34 return decorator
Decorator to time function execution time and print the results.
:params:
loops: How many times to execute the decorated function,
starting and stopping the timer before and after each loop.