- 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/
我有一个类似于以下的结构。 class A { string title; List bItem; } class B { int pric
本地流 和 远程流 两者都是“媒体流列表 ”。 本地流 包含“本地媒体流 ” 对象 但是,远程流 包含“媒体流 ” 对象 为什么差别这么大? 当我使用“本地流 “- 这个对我有用: localVide
我正在尝试将 8 列虚拟变量转换为 8 级排名的一列。 我试图用这个公式来做到这一点: =IF(OR(A1="1");"1";IF(OR(B1="1");"2";IF(OR(C1="1");"3";I
我正在使用面向对象编程在 Python 中创建一个有点复杂的棋盘游戏的实现。 我的问题是,许多这些对象应该能够与其他对象交互,即使它们不包含在其中。 例如Game是一个对象,其中包含PointTrac
有没有办法获取与 contains 语句匹配的最深元素? 基本上,如果我有嵌套的 div,我想要最后一个元素而不是父元素: Needle $("div:contains('Needle')")
出于某种原因,我无法在 Google 上找到答案!但是使用 SQL contains 函数我怎么能告诉它从字符串的开头开始,即我正在寻找等同于的全文 喜欢 'some_term%'。 我知道我可以使用
我正在尝试创建一个正则表达式来匹配具有 3 个或更多元音的字符串。 我试过这个: [aeiou]{3,} 但它仅在元音按顺序排列时才有效。有什么建议吗? 例如: 塞缪尔 -> 有效 琼 -> 无效 S
嘿所以我遇到了这样的情况,我从数据库中拉回一个客户,并通过包含的方式包含所有案例研究 return (from c in db.Clients.Include("CaseStudies")
如果关键字是子字符串,我无法弄清楚为什么这个函数不返回结果。 const string = 'cake'; const substring = 'cak'; console.log(string.in
我正在尝试将包含特定文本字符串的任何元素更改为红色。在我的示例中,我可以将子元素变为蓝色,但是我编写“替换我”行的方式有些不正确;红色不会发生变化。我注意到“contains”方法通常写为 :cont
我想问一下我是否可以要求/包含一个语法错误的文件,如果不能,则require/include返回一个值,这样我就知道所需/包含的文件存在语法错误并且不能被要求/包含? file.php语法错误 inc
我想为所有包含youtube链接的链接添加一个rel。 这就是我正在使用的东西-但它没有用。有任何想法吗? $('a [href:contains(“youtube.com”)]')。attr('re
我正在尝试在 Elasticsearch 中查询。除搜索中出现“/”外,此功能均正常运行。查询如下所示 GET styling_rules/product_line_filters/_search {
我正在开发名为eBookRepository的ASP.NET MVC应用程序,其中包含在线图书。 电子书具有自己的标题,作者等。因此,现在我正在尝试实现搜索机制。我必须使用Elasticsearch作
我已阅读Firebase Documentation并且不明白什么是 .contains()。 以下是文档中 Firebase 数据库的示例规则: { "rules": { "rooms"
我的问题是我可以给出条件[ 'BookTitleMaster.id' => $xtitid, ] 如下所示 $bbookinfs = $this->BookStockin->BookIssue->fi
我需要能够使用 | 检查模式在他们中。例如,对于像“dtest|test”这样的字符串,像 d*|*t 这样的表达式应该返回 true。 我不是正则表达式英雄,所以我只是尝试了一些事情,例如: Reg
我想创建一个正则表达式来不匹配某些单词... 我的字符:var test = "é123rr;and;ià456;or;456543" 我的正则表达式:test.match(\((?!and)(?!o
我在 XSLT 中有一个名为 variable_name 的变量,如果相关产品具有名称为 A 或 B 或两者均为 A & 的属性,我将尝试将其设置为 1 B.
您好,我想让接待员和经理能够查看工作类型和费率并随后进行更新。但是技术人员只能查看不能更新。该图是否有效? 我读到扩展用例是由发起基本用例的参与者发起的。我应该如何区分技术人员只能启动基本案例而不能启
我是一名优秀的程序员,十分优秀!