Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用decorator记录来自特定模块的所有函数调用?_Python_Arcpy - Fatal编程技术网

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”],您就可以完全控制代码的哪些部分会使用包装器,哪些部分不会(您甚至可以在全局命名空间中同时使用它们,并根据需要使用它们),因此它与手动添加装饰器在任何形状或形式上都没有区别,除了方便得多之外,这真是难以置信的好。非常感谢,我不必进行为期两周的搜寻来了解生成器、反射和检查包。谢谢:)