Python işlevlerini (kod + kapanışları) serileştirmeye çalışıyorum ve daha sonra bunları yeniden eski durumuna getiriyorum. Bu yazının en altındaki kodu kullanıyorum.Kapaması Python'da döngüleri olan bir işlevi geri yükleyebilir miyim?
Bu çok esnek bir koddur. İşlevinizden kapatılması işlevler olsa bile
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
Bu çağrılar çalışacaktır: İç fonksiyonların seri ve deserialisation sağlar ve böyle kendi bağlamı ihtiyacı olanlar olarak kapanışları olan fonksiyonlar eski haline getirilmeye kapanışlarında ve benzeri işlevlerde (kapanışların, daha fazla işlev içeren ve benzer işlevlere sahip kapaklar içeren işlevler içeren bir grafiğe sahibiz).
Bununla birlikte, bu grafikler döngüleri içerebilir çıkıyor:
def g1():
def g2():
g2()
return g2()
g = g1()
I (g
ile) g2
'nin kapatma bakarsak, İçinde g2
görebilir:
>>> g
<function g2 at 0x952033c>
>>> g.func_closure[0].cell_contents
<function g2 at 0x952033c>
Bu fonksiyonun işlevini kaldırmaya çalıştığımda ciddi bir soruna neden olur, çünkü her şey değişmezdir. aşağıdaki gibi newg2closure
oluşturulur
newg2 = types.FunctionType(g2code, globals, closure=newg2closure)
: Ne yapmak gerek işlevini newg2
yapmaktır
newg2closure = (make_cell(newg2),)
elbette yapılamaz hangi; Her kod satırı diğerine dayanır. Hücreler değişmezdir, tupler değişmezdir, fonksiyon tipleri değişmezdir.
Peki, ne bulmaya çalışıyorum, yukarıda newg2
yaratmak için bir yol var mı? Bu nesnenin kendi kapanış grafiğinde yer aldığı bir işlev türü nesnesi oluşturabilmem için bir yol var mı?
Python 2.7 kullanıyorum (App Engine'deyim, bu yüzden Python 3'e gidemiyorum).
Başvuru için, benim seri fonksiyonları:
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
Bu çok ilginç bir soru ve yanıtlayacağımı bilmiyorum. C api'ye gitmek hiç yardımcı olur mu? İnsanların bu tür kodları çalıştırdığımdan önce bu şekilde kapanışlarını gördüm http://pythondoeswhat.blogspot.com/2012/11/back-porting-non-local.html Bir segfault yüzden bu linkin ne kadar okunaklı olduğundan emin değilim. –
Python için C kodunu okuyorum, bu çalışmayı o seviyede yapabilirsiniz - bütün nesneler değişebilir - ama oraya giremiyorum. Ben appengine'ı hedefliyorum, bu yüzden yaptığım her şeyin saf python olması gerektiğini düşünüyorum. –
Not: Kendi nesnelerinizi hücre yerine koyamazsınız. Denedim :-) . Types.FunctionType() c uygulanması dikkatlice bir tuple hücreleri geçti, ördek yazarak izin verilen kontrol eder. –