在python中,我试图编写一个实用函数来计算函数运行的时间,它基本上是一个帮助函数,可以使timeit
更容易使用。
下面是我的代码。如果有任何看起来奇怪的地方,那是因为我试图尽可能多地修剪代码,使其尽可能简单:
import numpy as np
import timeit
import requests
from enum import Enum
import copy
class LoggingLevel(Enum):
Debug = 1
Info = 2
Important = 3
VeryImportant = 4
SuperImportant = 5
Warning = 6
class Logging:
@staticmethod
def log(message: str, level: LoggingLevel, special, colorized):
colors = {
"Debug": "\033[0m",
"Info": "\033[94m",
"Important": "\033[95m",
"VeryImportant": "\033[96m",
"SuperImportant": "\033[93m",
"Warning": "\033[91m",
"Special": "\033[92m",
"reset": "\033[0m"
}
if colorized:
if special:
print(f"{colors['Special']}[{level.name}] [Special]: {message}{colors['reset']}")
else:
if level.name in colors:
print(f"{colors[level.name]}[{level.name}]: {message}{colors['reset']}")
else:
print(f"[{level.name}]: {message}")
logging = Logging()
def check_internet(testurl: str = "https://www.example.com", timeout: float = 5) -> bool:
logging.log("Checking for internet connection with timeout of"
f" {timeout if timeout is not None else ''} seconds...",
LoggingLevel.Info, special=False, colorized=True)
logging.log(f"Using {testurl} to check for internet connection", LoggingLevel.Debug, special=False, colorized=True)
try:
requests.get(testurl, timeout=timeout)
logging.log(f"Successfully confirmed internet connection!", LoggingLevel.Info, special=False, colorized=True)
return True
except (requests.ConnectionError, requests.Timeout):
return False
def time(code: str, useglobals: bool = True, sets: int = 3, trialsperset: int = 10) -> float:
"""
Times how long a segment of code takes to run (on average) using the timeit module
Usually used to test functions
:param code: The segment of code to test
:param useglobals: Whether to use the current globals or no globals in the
timing sandbox (the code may not work without them)
:param sets: The number of sets
:param trialsperset: The number of times to run the code each set
(Total number of times run = sets * trials)
the higher the number, the more accurate, but also the longer it will take
:return: Average amount of time the code takes to run (seconds)
"""
# noinspection IncorrectFormatting
class NopClass:
""" From https://stackoverflow.com/a/24946360/20558255 """
def nop(*args, **kwargs): pass
def __getattr__(self, _): return self.nop
nopclass = NopClass()
nopfunction: callable = lambda *args, **kwargs: None
logging.log(f"Testing how long {code} takes to run in {sets} sets"
f" of {trialsperset} trials...", LoggingLevel.Debug, special=False, colorized=True)
if useglobals:
sandboxglobals = copy.deepcopy(globals())
# We nop logging class and print function so we don't get flooded with print messages
sandboxglobals["print"] = nopfunction
sandboxglobals["logging"] = nopclass
else:
sandboxglobals = None
times = timeit.repeat(stmt=code, repeat=sets, number=trialsperset, globals=sandboxglobals)
return np.mean(times)
time("check_internet()", useglobals=True, sets=3, trialsperset=10)
希望你能理解为什么我(尝试)将globals()
复制到sandboxglobals
,并对sandboxglobals
进行一些更改,然后将sandboxglobals
传递给timeit.repeat
:我想禁用打印和日志记录的代码 * 当它被计时 *.然而,我不想禁用打印和日志记录的真实的的程序.虽然在这种情况下,将被禁用打印和日志记录的真正的程序调用timeit.repeat()
之前,然后重新启用它们后,在其他情况下(异步或多线程代码,例如),这将是重要的.
然而,deepcopy
不工作。当我运行代码时,我得到以下错误:
Traceback (most recent call last):
File "Test.py", line 98, in <module>
time("check_internet()", useglobals=True, sets=3, trialsperset=10)
File "Test.py", line 87, in time
sandboxglobals = copy.deepcopy(globals())
File "C:\Users\zachy\AppData\Local\Programs\Python\Python310\lib\copy.py", line 146, in deepcopy
y = copier(x, memo)
File "C:\Users\zachy\AppData\Local\Programs\Python\Python310\lib\copy.py", line 231, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "C:\Users\zachy\AppData\Local\Programs\Python\Python310\lib\copy.py", line 161, in deepcopy
rv = reductor(4)
TypeError: cannot pickle 'module' object
我明白这个错误是什么意思,但我不知道如何解决它。我尝试了所有我能找到的方法,但我无法找到一种方法来深度复制而不pickle。
浅拷贝不起作用,因为它不是递归的-它将禁用print
,因为这是globals()
dict中的顶级,但它不会禁用logging.log
。作为证明,这里是将deepcopy
更改为copy
后的日志:
[Debug]: Testing how long check_internet() takes to run in 3 sets of 10 trials...
[Info]: Checking for internet connection with timeout of 5 seconds...
[Debug]: Using https://www.example.com to check for internet connection
[Info]: Successfully confirmed internet connection!
[Info]: Checking for internet connection with timeout of 5 seconds...
[Debug]: Using https://www.example.com to check for internet connection
[Info]: Successfully confirmed internet connection!
... [TRUNCATED]
有没有什么方法可以实现我想要的?或者是不可能的?我是否错过了什么?谢谢。
1条答案
按热度按时间lc8prwob1#
由于您不需要对
sandboxglobals
中的模块信息进行任何修改,因此您可以跳过从globals
深度复制它们。