- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试序列化 Python 函数(代码 + 闭包),并在稍后恢复它们。我正在使用本文底部的代码。
这是非常灵活的代码。它允许内部函数和闭包函数的序列化和反序列化,例如那些需要恢复其上下文的函数:
def f1(arg):
def f2():
print arg
def f3():
print arg
f2()
return f3
x = SerialiseFunction(f1(stuff)) # a string
save(x) # save it somewhere
# later, possibly in a different process
x = load() # get it from somewhere
newf2 = DeserialiseFunction(x)
newf2() # prints value of "stuff" twice
即使函数的闭包中有函数,它们的闭包中有函数等等,这些调用也会起作用(我们有一个闭包图,其中闭包包含具有包含更多函数的闭包的函数等等) .
然而,事实证明这些图可以包含循环:
def g1():
def g2():
g2()
return g2()
g = g1()
如果我查看 g2
的闭包(通过 g
),我可以在其中看到 g2
:
>>> g
<function g2 at 0x952033c>
>>> g.func_closure[0].cell_contents
<function g2 at 0x952033c>
当我尝试反序列化函数时,这会导致严重的问题,因为一切都是不可变的。我需要做的是使函数 newg2
:
newg2 = types.FunctionType(g2code, globals, closure=newg2closure)
其中 newg2closure
的创建方式如下:
newg2closure = (make_cell(newg2),)
这当然是做不到的;每行代码都相互依赖。元胞是不可变的,元组是不可变的,函数类型是不可变的。
所以我想知道的是,有没有办法在上面创建 newg2
?有什么方法可以创建一个函数类型对象,该对象在其自己的闭包图中被提及?
我正在使用 python 2.7(我在 App Engine 上,所以我不能转到 Python 3)。
作为引用,我的序列化函数:
def SerialiseFunction(aFunction):
if not aFunction or not isinstance(c, types.FunctionType):
raise Exception ("First argument required, must be a function")
def MarshalClosureValues(aClosure):
logging.debug(repr(aClosure))
lmarshalledClosureValues = []
if aClosure:
lclosureValues = [lcell.cell_contents for lcell in aClosure]
lmarshalledClosureValues = [
[marshal.dumps(litem.func_code), MarshalClosureValues(litem.func_closure)] if hasattr(litem, "func_code")
else [marshal.dumps(litem)]
for litem in lclosureValues
]
return lmarshalledClosureValues
lmarshalledFunc = marshal.dumps(aFunction.func_code)
lmarshalledClosureValues = MarshalClosureValues(aFunction.func_closure)
lmoduleName = aFunction.__module__
lcombined = (lmarshalledFunc, lmarshalledClosureValues, lmoduleName)
retval = marshal.dumps(lcombined)
return retval
def DeserialiseFunction(aSerialisedFunction):
lmarshalledFunc, lmarshalledClosureValues, lmoduleName = marshal.loads(aSerialisedFunction)
lglobals = sys.modules[lmoduleName].__dict__
def make_cell(value):
return (lambda x: lambda: x)(value).func_closure[0]
def UnmarshalClosureValues(aMarshalledClosureValues):
lclosure = None
if aMarshalledClosureValues:
lclosureValues = [
marshal.loads(item[0]) if len(item) == 1
else types.FunctionType(marshal.loads(item[0]), lglobals, closure=UnmarshalClosureValues(item[1]))
for item in aMarshalledClosureValues if len(item) >= 1 and len(item) <= 2
]
lclosure = tuple([make_cell(lvalue) for lvalue in lclosureValues])
return lclosure
lfunctionCode = marshal.loads(lmarshalledFunc)
lclosure = UnmarshalClosureValues(lmarshalledClosureValues)
lfunction = types.FunctionType(lfunctionCode, lglobals, closure=lclosure)
return lfunction
最佳答案
这是一个有效的方法。
你无法修复这些不可变对象(immutable对象),但你可以做的是用代理函数代替循环引用,并让它们在全局字典中查找真正的函数。
1:序列化时,跟踪您看到的所有函数。如果您再次看到相同的值,请不要重新序列化,而是序列化一个标记值。
我用过一套:
lfunctionHashes = set()
对于每个序列化项目,检查它是否在集合中,如果是,则使用标记,否则将其添加到集合中并正确编码:
lhash = hash(litem)
if lhash in lfunctionHashes:
lmarshalledClosureValues.append([lhash, None])
else:
lfunctionHashes.add(lhash)
lmarshalledClosureValues.append([lhash, marshal.dumps(litem.func_code), MarshalClosureValues(litem.func_closure, lfullIndex), litem.__module__])
2: 反序列化时,保留一个全局的functionhash: function字典
gfunctions = {}
在反序列化过程中,任何时候反序列化一个函数,将它添加到 gfunctions。在这里,item 是(散列、代码、闭包值、模块名称):
lfunction = types.FunctionType(marshal.loads(item[1]), globals, closure=UnmarshalClosureValues(item[2]))
gfunctions[item[0]] = lfunction
当你遇到一个函数的哨兵值时,使用代理,传入函数的哈希值:
lfunction = make_proxy(item[0])
这是代理。它根据散列查找真正的函数:
def make_proxy(f_hash):
def f_proxy(*args, **kwargs):
global gfunctions
f = lfunctions[f_hash]
f(*args, **kwargs)
return f_proxy
我还必须进行一些其他更改:
这是完整的新代码。
lfunctions = {}
def DeserialiseFunction(aSerialisedFunction):
lmarshalledFunc, lmarshalledClosureValues, lmoduleName = pickle.loads(aSerialisedFunction)
lglobals = sys.modules[lmoduleName].__dict__
lglobals["lfunctions"] = lfunctions
def make_proxy(f_hash):
def f_proxy(*args, **kwargs):
global lfunctions
f = lfunctions[f_hash]
f(*args, **kwargs)
return f_proxy
def make_cell(value):
return (lambda x: lambda: x)(value).func_closure[0]
def UnmarshalClosureValues(aMarshalledClosureValues):
global lfunctions
lclosure = None
if aMarshalledClosureValues:
lclosureValues = []
for item in aMarshalledClosureValues:
ltype = len(item)
if ltype == 1:
lclosureValues.append(pickle.loads(item[0]))
elif ltype == 2:
lfunction = make_proxy(item[0])
lclosureValues.append(lfunction)
elif ltype == 4:
lfuncglobals = sys.modules[item[3]].__dict__
lfuncglobals["lfunctions"] = lfunctions
lfunction = types.FunctionType(marshal.loads(item[1]), lfuncglobals, closure=UnmarshalClosureValues(item[2]))
lfunctions[item[0]] = lfunction
lclosureValues.append(lfunction)
lclosure = tuple([make_cell(lvalue) for lvalue in lclosureValues])
return lclosure
lfunctionCode = marshal.loads(lmarshalledFunc)
lclosure = UnmarshalClosureValues(lmarshalledClosureValues)
lfunction = types.FunctionType(lfunctionCode, lglobals, closure=lclosure)
return lfunction
def SerialiseFunction(aFunction):
if not aFunction or not hasattr(aFunction, "func_code"):
raise Exception ("First argument required, must be a function")
lfunctionHashes = set()
def MarshalClosureValues(aClosure, aParentIndices = []):
lmarshalledClosureValues = []
if aClosure:
lclosureValues = [lcell.cell_contents for lcell in aClosure]
lmarshalledClosureValues = []
for index, litem in enumerate(lclosureValues):
lfullIndex = list(aParentIndices)
lfullIndex.append(index)
if isinstance(litem, types.FunctionType):
lhash = hash(litem)
if lhash in lfunctionHashes:
lmarshalledClosureValues.append([lhash, None])
else:
lfunctionHashes.add(lhash)
lmarshalledClosureValues.append([lhash, marshal.dumps(litem.func_code), MarshalClosureValues(litem.func_closure, lfullIndex), litem.__module__])
else:
lmarshalledClosureValues.append([pickle.dumps(litem)])
lmarshalledFunc = marshal.dumps(aFunction.func_code)
lmarshalledClosureValues = MarshalClosureValues(aFunction.func_closure)
lmoduleName = aFunction.__module__
lcombined = (lmarshalledFunc, lmarshalledClosureValues, lmoduleName)
retval = pickle.dumps(lcombined)
return retval
关于python - 我可以恢复闭包包含 Python 循环的函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26250895/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!