Экземпляр класса становится непригодным для обработки (укроп), когда функция ограничения и параметры определены внутри области класса

Чтобы диагностировать проблему распаковки dill с объектами lmfit, я хотел попробовать включить определение моей ограничивающей функции в класс, экземпляр которого я позже распарслю. Однако сброс рассола dill, где функция ограничения определена внутри области класса, вызывает RuntimeError: maximum recursion depth exceeded (раздел (3) кода ниже).

Я не могу придумать интуитивной причины, почему это должно быть так. Например, если я помещаю функцию области класса в OrderedDict области класса, экземпляр класса остается dill доступным для выбора (раздел (1) кода ниже).

Те, кто знаком с lmfit: есть идеи, почему lmfit / asteval вызывают такое поведение?

Те, кто знаком с ООП, но не 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)

person PetMetz    schedule 14.12.2017    source источник


Ответы (1)


Вы определяете 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 должна быть "нормальной" функцией. Если вы не используете staticmethod, Python привяжет метод к экземпляру. Эта привязка запускает рекурсию.

person Mike Müller    schedule 14.12.2017