Python 如何使用decorator记录来自特定模块的所有函数调用?
一些背景: 我正在尝试为日志编写一个装饰程序。具体来说,我经常使用Python 如何使用decorator记录来自特定模块的所有函数调用?,python,arcpy,Python,Arcpy,一些背景: 我正在尝试为日志编写一个装饰程序。具体来说,我经常使用arcpy,从工具中获取消息的方法是使用arcpy.GetMessages()。然而,这是一种恼人的功能,因为它只保存最近的消息,并且必须在每个工具之后调用。伪代码示例 import arcpy import logging log = logging.getLogger(__name__) def test_function(in_data): out_data = 'C:/new_path/out_data'
arcpy
,从工具中获取消息的方法是使用arcpy.GetMessages()
。然而,这是一种恼人的功能,因为它只保存最近的消息,并且必须在每个工具之后调用。伪代码示例
import arcpy
import logging
log = logging.getLogger(__name__)
def test_function(in_data):
out_data = 'C:/new_path/out_data'
arcpy.MakeFeatureLayer_management(in_data, out_data)
log.info(arcpy.GetMessages())
arcpy.Delete_management(in_data)
log.info(arcpy.GetMessages())
# If you did log.info(arcpy.GetMessages()) again here you'd just get
# the message from the Delete tool again
最好编写一个decorator,它可以在调用arcpy
函数时识别并记录它。比如:
def log_the_arcpy(fn):
@functools.wraps(fn)
def inner(*args, **kwargs):
result = fn(*args, **kwargs)
# Some magic happens here?!
if module_parent == arcpy: #module_parent is obviously fake, is there a real attribute?
log.info(arcpy.GetMessages())
return result
return inner
然而,我在两个方面陷入了困境:(1)如何识别单个函数的“arcpy ness”(或任何包),以及(2)使用装饰器挖掘函数内部并确定潜在多个函数调用的包成员身份的总体方法
似乎有用的部分有:
- 使用hasattr(但似乎不太正确/可能非常慢?)
- 使用反射(像这样)或
- 使用
和/或生成器暂停执行的一些魔法inspect
if hasattr(fn, '__module__') and getattr(fn, '__module__') == 'arcpy':
log.info(arcpy.GetMessages())
全功能:
def log_the_arcpy(fn):
@functools.wraps(fn)
def inner(*args, **kwargs):
result = fn(*args, **kwargs)
if hasattr(fn, '__module__') and getattr(fn, '__module__') == 'arcpy':
log.info(arcpy.GetMessages())
return result
return inner
如果要直接在
arcpy
上调用方法,包装模块可能是最简单、对性能影响最小的方法:
# arcpy_proxy.py
import arcpy as _arcpy
import logging
class _proxy(object):
def __getattr__(self, item):
ref = getattr(_arcpy, item)
if callable(ref): # wrap only function calls
return self._wrap(ref)
return ref
@classmethod
def _wrap(cls, func):
def inner(*args, **kwargs):
val = func(*args, **kwargs)
logging.info(_arcpy.GetMessages()) # log the messages
return val
return inner
arcpy = _proxy()
然后,您只需从arcpy_proxy导入arcpy,作为替代品。您甚至可以在主脚本中添加
sys.modules[“arcpy”]=arcpy
(当然是在导入之后),这样您就不必在其他任何地方替换它来代理它了。很抱歉,太密集了-您能将它转换成类似于我的第二个代码示例的东西吗?我对装饰师也很陌生,所以我不确定这到底是怎么回事——因为我的大脑认为fn
是整个函数,很难理解如何测试“模块”=='arcpy'
中的所有函数fn
请尝试一下。它不起作用——我想是因为fn
不在模块arcpy
(我正在使用我编写的一个普通函数,它类似于我的示例中的test\u函数()
——如果不清楚,我想修饰我编写的函数,其中包括arcpy
)。这给了我一些关于如何在fn/test\u函数中测试函数调用的想法,
…@HFBrowning-为了方便,我必须牺牲一些东西;)只要不使用它替换sys.modules[“arcpy”],您就可以完全控制代码的哪些部分会使用包装器,哪些部分不会(您甚至可以在全局命名空间中同时使用它们,并根据需要使用它们),因此它与手动添加装饰器在任何形状或形式上都没有区别,除了方便得多之外,这真是难以置信的好。非常感谢,我不必进行为期两周的搜寻来了解生成器、反射和检查包。谢谢:)