【问题标题】:How to add suffix operations for all python functions?如何为所有python函数添加后缀操作?
【发布时间】:2022-01-21 01:29:25
【问题描述】:

我在文件 myfile.py 中有一组函数,我想为每个函数自动添加一个计时器打印: (有大约 700 个功能)

def myfunXXX() 
   mytime.start()

   mytime.end() 

mytime.start(): to= time.time()
mytime.end():   print(time.time() - t0)

目前的解决方案是:

  1. 为所有函数手动添加装饰器。
  2. 在所有函数中添加代码sn-p

有没有办法“破解” Python 和函数库定义 在执行之前和执行结束时添加这两个函数 对于一组 Python 函数?

也许使用 AST 并注入一些字符串代码?

【问题讨论】:

  • 装饰器有什么问题?
  • 我需要将装饰器添加到代码中的500个函数中。喜欢自动的东西
  • 您可能可以正则表达式搜索并将装饰器替换到函数声明中。
  • 您确定不只是想使用普通的分析器吗?
  • python - Viewing all defined variables - Stack Overflow ?然后检查哪些是函数和补丁。

标签: python function


【解决方案1】:

sys.setprofile 正是为此而生的。

确保您根据frame.f_code.co_filename 进行过滤,以仅在想要的文件上停止。

在调用事件时启动计时器,在返回时停止。

确保使用time.perf_counter 作为计时器。其他的不太可靠。

请记住,与检查模块中所有函数(尤其是用 Python 编写的函数)的任何其他分析器一样,它会降低您的代码速度。


例子:

import sys, time


def create_profile_function(filename):
    _active_frames = {}

    def profile_func(frame, event, arg):
        if event == "call" and frame.f_code.co_filename == filename:
            _active_frames[frame] = time.perf_counter()
        elif event == "return" and frame in _active_frames:
            print(frame.f_code.co_name,
                  time.perf_counter() - _active_frames.pop(frame))

    return profile_func

sys.setprofile(create_profile_function(__file__))

def test():
    print("rawr")
    pass

test()

输出:

rawr
test 0.0005169999785721302

【讨论】:

  • 我仍然怀疑他们是否真的需要这样的自定义分析代码,而不是仅仅使用现有的分析器,但无论如何都很有趣。
  • @KellyBundy 他可能需要修改或按需打印,不知道:-)
  • 这不是必要的分析,更多的是在退出时获得 500 个函数列表的时间(来自一个模块 .py)
  • @quantCode 我的答案仍然有效
  • 谢谢,你能写一个完整且最小的例子吗?之后才会批准。
【解决方案2】:

如果您愿意修改调用这些函数的位置,一个解决方案是执行以下操作:

import time
def wrapper(function,args):
    start = time.time()
    function(args)
    end = time.time()
    print(end-start)

我知道你不想添加装饰器,因为你有很多函数可以添加它们。如果您愿意将您的函数放在一个类中,您可能会发现 this 答案或 this 答案对于自动向类添加装饰器很有用。

【讨论】:

    【解决方案3】:

    Patch Classes 是一种“hack”的装饰器。

    def _task(cls):
       og_attrs = cls.__getattribute__
       def new_getattrs(self, name):
           return og_attrs(self, name)
       cls.__getattribute__ = new_getattrs
       return cls 
    
    @_task # mass change in class method's behavior
    class A:
        def reborn_function(self):
            pass
    
    

    您的整个问题可能不会立即消失。但这是你必须向后兼容和优雅的最接近的东西。如果您担心 API 更改或向后兼容性,Ast 将是错误的选择。

    【讨论】:

      猜你喜欢
      • 2017-08-26
      • 1970-01-01
      • 1970-01-01
      • 2013-02-04
      • 2022-07-06
      • 1970-01-01
      • 2013-09-25
      • 2018-07-22
      • 2018-11-01
      相关资源
      最近更新 更多