class 当约束函数和参数在 class 范围内定义时,实例变得不可(莳萝)腌制

class instance becomes un(dill)pickleable when constraint function and Parameters defined inside class scope

为了诊断一个 dill unpickling 问题 lmfit 对象,我想尝试在 class 我稍后会腌制其实例。但是,在 class 范围内定义约束函数的地方转储 dill pickle 会引发 RuntimeError: maximum recursion depth exceeded(下面代码的第 (3) 节)。

我想不出为什么会是这种情况的直观原因。例如,如果我将一个 class-scope 函数填充到一个 class-scope OrderedDict 中,class 实例仍然是 dill 可腌制的(部分(1 ) 下面的代码)。

熟悉 lmfit 的人: 知道为什么 lmfit / asteval 正在触发此行为?

那些熟悉 OOP 但不熟悉的人 lmfit: 对可能导致此类问题的代码类型有什么想法吗?

谢谢!

import dill
import lmfit
from collections import OrderedDict as od

# Python 2.7.13; dill 0.2.7.1; lmfit 0.9.7; numpy 1.13.3; scipy 1.0.0

#%% 1) this works ####################################
class test(object):

    def inside_func(*args):
        return

    def __init__(self):
        # check OrderedDict dill-pickleable (should be)
        self.d = od([])
        self.d.update({'func': self.inside_func})
        return

t = test()

with open('test.pkl', 'wb') as f:
    dill.dump(t, f)


#%% 2) this also works ###############################

def outside_func(*args):
    return

class test(object):

    def __init__(self):
        # some dummy Parameters set 
        self.p = lmfit.Parameters()
        self.p.add('var1')
        self.p.add('var2')

        # addition of 'func' to _asteval's symtable from outside class scope
        self.p._asteval.symtable['func'] = outside_func
        return

t = test()

with open('test.pkl', 'wb') as f:
    dill.dump(t, f)



#%% 3) this doesn't work ###############################

class test(object):
    def inside_func(*args):
        return

    def __init__(self):
        # some dummy Parmaeters set
        self.p = lmfit.Parameters()
        self.p.add('var1')
        self.p.add('var2')

        # addition of 'func' to _asteval's symtable from inside class scope
        if not any('func' == x for x in self.p._asteval.symtable.keys()):
            self.p._asteval.symtable.update({'func': self.inside_func})
        return

t = test()

with open('test.pkl', 'wb') as f:
    dill.dump(t, f)

你在错误的地方定义了inside_func。在 __init__.

中完成

这个有效:

class test(object):

    def __init__(self):

        def inside_func(*args):
            return

        # some dummy Parmaeters set
        self.p = lmfit.Parameters()
        self.p.add('var1')
        self.p.add('var2')

        # addition of 'func' to _asteval's symtable from inside class scope
        if not any('func' == x for x in self.p._asteval.symtable.keys()):
            self.p._asteval.symtable.update({'func': inside_func})
        return

t = test()

with open('test.pkl', 'wb') as f:
    dill.dump(t, f)

或者,将其设为静态方法:

class test(object):

    @staticmethod
    def inside_func(*args):
        return

    def __init__(self):
        # some dummy Parmaeters set
        self.p = lmfit.Parameters()
        self.p.add('var1')
        self.p.add('var2')

        # addition of 'func' to _asteval's symtable from inside class scope
        if not any('func' == x for x in self.p._asteval.symtable.keys()):
            self.p._asteval.symtable.update({'func': self.inside_func})
        return

t = test()

with open('test.pkl', 'wb') as f:
    dill.dump(t, f)

self.inside_func 需要是一个 "normal" 函数。如果不使用 staticmethod,Python 会将方法绑定到实例。此绑定触发递归。