python - 如何在不积极修改代码的情况下扩展日志记录?[编写干净的代码]
问题描述
假设我有一个calculate()
计算复杂的方法,其中包含许多变量,而我想记录不同阶段的变量值是多少(编辑:不仅用于验证,还用于数据研究目的)。例如。
# These assignment are arbitrary,
# but my calculate() method is more complex
def calculate(a, b):
c = 2*a+b
d = a-b
if c > d+10:
g = another_calc(a, c):
else:
g = another_calc(a, d):
return c, d, g
def another_calc(a, c_d):
e = a+c_d
f = a*c_d
g = e+f
return g
您可能会假设该方法将进行大量修改以进行实验探索。这里没有太多日志记录,我想记录发生的事情,例如我可以编写这样的激进代码
# These assignment are arbitrary,
# but my calculate() method is more complex
def calculate(a, b):
info = {"a": a, "b": b}
c = 2*a+b
d = a-b
info["c"], info["d"] = c, d
if c > d+10:
info["switch"] = "entered c"
g, info = another_calc(a, c, info):
else:
info["switch"] = "entered d"
g, info = another_calc(a, d, info):
return c, d, g, info
def another_calc(a, c_d, info):
e = a+c_d
f = a*c_d
g = e+f
info["e"], info["f"], info["g"] = e, f, g
return g, info
这符合我的目的(我得到了 info 对象,然后将其导出为 CSV 以供我进一步研究)但是在原始 clean 方法中添加更多(非功能性)行calculate()
、更改签名和返回值是非常难看的。
但是我可以写一个更干净的代码吗? 我在想是否可以使用装饰器来包装这个方法。希望你们能有一些很好的答案。谢谢。
解决方案
编写更简洁代码的一种方法(我的观点)是将 info -dictionary 包装在一个类中。
这是我的简单代码示例:
# These assignment are arbitrary,
# but my calculate() method is more complex
def calculate(a, b, logger):
logger.log("a", a)
logger.log("b", b)
c = 2*a+b
d = a-b
logger.log("c", c)
logger.log("d", d)
if c > d+10:
logger.log("switch", "entered c")
g = another_calc(a, c)
else:
logger.log("switch", "entered d")
g = another_calc(a, d)
return c, d, g
def another_calc(a, c_d, logger):
e = a+c_d
f = a*c_d
g = e+f
logger.log("e", e)
logger.log("f", f)
logger.log("g", g)
return g
class Logger(object):
data = []
def log(self, key, value):
self.data.append({key: value})
def getLog(self):
return self.data
logger = Logger()
print(calculate(4, 7, logger))
print(logger.getLog())
优点和缺点
我在这里使用单独的记录器类,因为这样我就不需要知道记录器是如何实现的。在示例中,它只是一个简单的字典,但如果需要,您可以更改创建新记录器的实现。
此外,您可以选择如何打印数据或选择输出。也许你可以有一个 Logger 的接口。
我使用字典是因为看起来您只需要键值对。
现在,使用记录器,我们需要更改方法签名。当然,例如,您可以将默认值定义为 None。然后应该一直检查 None 值,但这就是我没有定义默认值的原因。如果您拥有代码并且可以更改该方法的每个引用calculate()
,那么这应该不是问题。
还有一件有趣的事情在以后可能很重要。当您调试了输出并且不再需要记录任何内容时,您就可以实现Null object。使用Null object
,您可以删除所有日志记录而无需再次更改代码。
我试图思考如何使用装饰器,但现在找到了任何好方法。如果只记录输出,那么装饰器就可以工作。
推荐阅读
- python - 无法查看所有用户输入值
- javascript - 控制器中未收到广播 - angularjs
- android - 在android片段中验证手机号码
- java - 如何在Java中获取for循环的最后一个值?
- windows - 在 Windows 上突出显示或下划线输出到标准输出
- java - 用于连续重复字母、数字和特殊字符的 Java 正则表达式
- javascript - Angular 6 typescript 与 KotlinJs 的集成
- reactjs - React 中的 .map() 问题
- python - 关于 Disconnected-RNN 的问题(发布于 ACL 2018)
- c++ - 为什么弹出我的堆栈返回垃圾而不是初始变量?