代码之家  ›  专栏  ›  技术社区  ›  herohaha

用于修改其他已定义函数的函数

  •  0
  • herohaha  · 技术社区  · 3 周前

    是否有方法编写一个接受某些参数的函数,以修改多个现有函数?

    例如,如果我有:

    def add(a, b):
        return a + b
    
    def minus(a, b):
        return a - b
    
    def offset_b(func, n):
        (??) func(a, b - n)
    

    那么我想执行以下操作:

    offset_b(add(1, 2), 0.5)
    offset_b(minus(1, 2), 0.5)
    

    我知道一种方法是:

    def new_b(b):
        return b-0.5
    
    add(1, new_b(b))
    minus(1, new_b(b))
    

    是否有方法使用包装器或其他东西来获取函数( add / minus )以及 n ,所以每次我输入一些 add(1, 2) 确实如此 add(1, 2 - 0.5) 而不是原始版本?

    1 回复  |  直到 3 周前
        1
  •  4
  •   ShadowRanger    3 周前

    定义一个函数,该函数接受具有已知参数的现有函数,并返回一个包装它的新函数:

    import functools  # To borrow wrapped function's docs nicely
    
    def offset_b(func, n):
        @functools.wraps(func)
        def wrapped(a, b):
            return func(a, b-n)
        return wrapped
    

    然后,您可以定义的新版本 add minus 应用偏移量:

    add_with_offset_1 = offset_b(add, 1)
    minus_with_offset_1 = offset_b(minus, 1)
    

    或者,如果你想制作一个合适的装饰器,将这种突变应用于一个新函数 只有 如果调用时应用了偏移量,则可以增加嵌套,以生成 decorator with parameters ,这样第一个调用就可以获取偏移量并返回一个函数,当与另一个函数一起调用时,该函数会生成包装函数:

    def offset_b(n):
        def do_wrap(func):
            @functools.wraps(func)
            def wrapped(a, b):
                return func(a, b-n)
            return wrapped
        return do_wrap
    

    这允许您像以前一样使用它,但顺序不同:

    offset_by_1 = offset_b(1)
    add_with_offset_1 = offset_by_one(add)  # Or as one-liner: add_with_offset_1 = offset_b(1)(add)
    minus_with_offset_1 = offset_by_one(minus)
    

    或者将其用作装饰器,立即修改包装函数:

    @offset_b(0.5)
    def add(a, b):
        return a + b
    
    @offset_b(0.5)
    def minus(a, b):
        return a - b
    

    所以 添加 立即存在,偏移量为 0.5 适用于所有调用(在这种情况下令人困惑,但在其他情况下很有用)。