如何在Python中对函数进行深度复制?

Tom*_*Tom 20 python copy function deep-copy

我想在Python中对函数进行深度复制.该副本模块是没有帮助的,根据文件,其中说:

此模块不复制类型,如模块,方法,堆栈跟踪,堆栈帧,文件,套接字,窗口,数组或任何类似类型.它通过返回原始对象来"复制"函数和类(浅和深); 这与pickle模块处理这些方式兼容.

我的目标是让两个函数具有相同的实现,但具有不同的文档字符串.

def A():
    """A"""
    pass

B = make_a_deepcopy_of(A)
B.__doc__ = """B"""
Run Code Online (Sandbox Code Playgroud)

那么怎么做呢?

Gle*_*ard 22

FunctionType构造函数用于制作函数的深层副本.

import types
def copy_func(f, name=None):
    return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
        f.func_defaults, f.func_closure)

def A():
    """A"""
    pass
B = copy_func(A, "B")
B.__doc__ = """B"""
Run Code Online (Sandbox Code Playgroud)

  • 仅适用于 python 2。请参阅下面的 [Aaron Hall's](/sf/answers/2150000961/) 帖子以获取与 py 2/3 兼容的答案。 (3认同)

Aar*_*all 13

我的目标是让两个函数具有相同的实现,但具有不同的文档字符串.

大多数用户会这样做,比如说原来的功能是old_module.py:

def implementation(arg1, arg2): 
    """this is a killer function"""
Run Code Online (Sandbox Code Playgroud)

并在 new_module.py

from old_module import implementation as _implementation

def implementation(arg1, arg2):
    """a different docstring"""
    return _implementation(arg1, arg2)
Run Code Online (Sandbox Code Playgroud)

这是重用功能的最直接方式.它易于阅读和理解意图.

不过,也许你有充分的理由提出你的主要问题:

如何在Python中对函数进行深度复制?

为了保持与Python 2 3的兼容性,我建议使用该函数的特殊__dunder__属性.例如:

import types

def copy_func(f, name=None):
    '''
    return a function with same code, globals, defaults, closure, and 
    name (or provide a new name)
    '''
    fn = types.FunctionType(f.__code__, f.__globals__, name or f.__name__,
        f.__defaults__, f.__closure__)
    # in case f was given attrs (note this dict is a shallow copy):
    fn.__dict__.update(f.__dict__) 
    return fn
Run Code Online (Sandbox Code Playgroud)

以下是一个示例用法:

def main():
    from logging import getLogger as _getLogger # pyflakes:ignore, must copy
    getLogger = copy_func(_getLogger)
    getLogger.__doc__ += '\n    This function is from the Std Lib logging module.\n    '
    assert getLogger.__doc__ is not _getLogger.__doc__
    assert getLogger.__doc__ != _getLogger.__doc__
Run Code Online (Sandbox Code Playgroud)

评论者说:

这不适用于内置函数

好吧,我不会为内置函数这样做.我没有理由为纯Python编写的函数执行此操作,我怀疑如果你这样做,你可能做了一些非常错误的事情(尽管我在这里可能是错的).

如果你想要一个执行内置函数功能的函数,并重用实现,就像复制一样,那么你应该用另一个函数包装函数,例如:

_sum = sum
def sum(iterable, start=0):
    """sum function that works like the regular sum function, but noisy"""
    print('calling the sum function')
    return _sum(iterable, start)
Run Code Online (Sandbox Code Playgroud)

  • 也许这种技术对于文档字符串来说并没有很好的动机,但我很高兴你写了这个教程,因为我真的需要它!我需要一组相互调用的函数的副本,将其复制到新的(动态)模块并调用彼此的副本,而不是原始版本。这意味着替换它们的“__globals__”以指向新模块。所有这一切的原因是 Numba 编译所有复制的函数而不影响原始函数,因为它们仍然需要在纯对象模式下访问。那谢谢啦! (2认同)

Jak*_*yer 7

from functools import partial

def a():
    """Returns 1"""
    return 1

b = partial(a)
b.__doc__ = """Returns 1, OR DOES IT!"""

print help(a)
print help(b)
Run Code Online (Sandbox Code Playgroud)

把它包裹成部分?

  • @JakobBowyer:使用这个解决方案你不会得到`a`的副本,但你在`functools.partial对象`中包装`a`. (2认同)