我想在Python中对函数进行深度复制。根据{{3}},副本模块没有帮助,它说:
此模块不复制模块,方法,堆栈跟踪,堆栈帧,文件等类型, 套接字,窗口,数组或任何类似的类型。它确实“复制”了函数和类(浅层) 通过返回原始对象不变;这与方式兼容 这些都是由泡菜模块处理的。
我的目标是让两个函数具有相同的实现,但具有不同的文档字符串。
def A():
"""A"""
pass
B = make_a_deepcopy_of(A)
B.__doc__ = """B"""
那怎么办呢?
答案 0 :(得分: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"""
答案 1 :(得分:12)
我的目标是让两个函数具有相同的实现,但具有不同的文档字符串。
大多数用户会这样做,比如原始功能在old_module.py
:
def implementation(arg1, arg2):
"""this is a killer function"""
并在new_module.py
from old_module import implementation as _implementation
def implementation(arg1, arg2):
"""a different docstring"""
return _implementation(arg1, arg2)
这是重用功能最直接的方法。它易于阅读和理解意图。
然而,也许你有充分的理由提出你的主要问题:
如何在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
以下是一个示例用法:
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__
评论者说:
这不适用于内置函数
对于内置函数,我不会 这个。我没有理由为使用纯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)
答案 2 :(得分: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)
将其包裹为部分?
答案 3 :(得分:3)
def A():
"""A"""
pass
def B():
"""B"""
return A()
答案 4 :(得分:1)
把它放在一个函数中:
def makefunc( docstring ):
def f():
pass
f.__doc__ = docstring
return f
f = makefunc('I am f')
g = makefunc("I am f too")
答案 5 :(得分:0)
其他答案不允许使用pickle进行序列化。这是我用来克隆函数并允许对python3进行序列化的代码:
import pickle
import dill
import types
def foo():
print ('a')
oldCode=foo.__code__
name='IAmFooCopied'
newCode= types.CodeType(
oldCode.co_argcount, # integer
oldCode.co_kwonlyargcount, # integer
oldCode.co_nlocals, # integer
oldCode.co_stacksize, # integer
oldCode.co_flags, # integer
oldCode.co_code, # bytes
oldCode.co_consts, # tuple
oldCode.co_names, # tuple
oldCode.co_varnames, # tuple
oldCode.co_filename, # string
name, # string
oldCode.co_firstlineno, # integer
oldCode.co_lnotab, # bytes
oldCode.co_freevars, # tuple
oldCode.co_cellvars # tuple
)
IAmFooCopied=types.FunctionType(newCode, foo.__globals__, name,foo.__defaults__ , foo.__closure__)
IAmFooCopied.__qualname__= name
print ( 'printing foo and the copy', IAmFooCopied, foo )
print ( 'dill output: ', dill.dumps(IAmFooCopied ))
print ( 'pickle Output: ', pickle.dumps (IAmFooCopied) )
输出:
printing foo and the copy <function IAmFooCopied at 0x7f8a6a8159d8> <function foo at 0x7f8a6b5f5268>
dill output: b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x00K\x00K\x00K\x02KCC\x0ct\x00d\x01\x83\x01\x01\x00d\x00S\x00q\x05NX\x01\x00\x00\x00aq\x06\x86q\x07X\x05\x00\x00\x00printq\x08\x85q\t)X\x10\x00\x00\x00testCloneFunc.pyq\nX\x0c\x00\x00\x00IAmFooCopiedq\x0bK\x05C\x02\x00\x01q\x0c))tq\rRq\x0ec__builtin__\n__main__\nh\x0bNN}q\x0ftq\x10Rq\x11.'
pickle Output: b'\x80\x03c__main__\nIAmFooCopied\nq\x00.'
如果您使用类方法尝试此代码段,则可能会遇到 qualname 属性的问题(我认为pickle应该找不到您的函数)。我从未尝试过,但是它应该很容易修复。只需查看有关质量名称
的文档答案 6 :(得分:0)
使用 lambda
和 rest 参数很容易做到:
def my_copy(f):
# Create a lambda that mimics f
g = lambda *args: f(*args)
# Add any properties of f
t = list(filter(lambda prop: not ("__" in prop),dir(f)))
i = 0
while i < len(t):
setattr(g,t[i],getattr(f,t[i]))
i += 1
return g
# Test
def sqr(x): return x*x
sqr.foo = 500
sqr_copy = my_copy(sqr)
print(sqr_copy(5)) # -> 25
print(sqr_copy(6)) # -> 36
print(sqr_copy.foo) # -> 500
print(sqr_copy == sqr) # -> False