Как не засолить объект, класс которого существует в различном пространстве имен (питон)?

Если у меня есть сценарий, который определяет класс:

script = """

class myClass:
    def __init__(self):
        self.name = 'apple'
        self.color = 'green'

"""

и затем должностное лицо этот сценарий в его собственном пространстве имен dict:

NS = {}
exec script in NS

и затем создайте случай класса и засолите его:

a = NS['myClass']()

import pickle

save = pickle.dumps(a)

Теперь, если я пытаюсь не засолить его:

load = pickle.loads(save)

Я получаю ошибку

AttributeError: 'module' object has no attribute 'myClass'

Я заключаю, что это не работает, потому что питон не знает, где найти myClass, чтобы восстановить объект. Но myClass действительно существует в НЕ УТОЧНЕНО dict. Есть ли способ сказать рассол, где найти класс для объекта, это загружает?

10
nl ja de

2 ответы

Можно на самом деле пойти один шаг вперед и иметь объект, восстанавливают себя в любой тип, который вы хотите.

import pickle
import copy_reg

class myClass(object):
    def __init__(self):
        self.apple = 'banana'

class otherclass(object):
    def __init__(self):
        self.apple = 'existential woe'

def pickle_an_object(o):
    print "pickling %s" % str(o)
    return otherclass, (o.apple,)

copy_reg.pickle(myClass, pickle_an_object)

foo = myClass()

s = pickle.dumps(foo)

del myClass
del otherclass

class otherclass(object):
    def __init__(self, appletype):
        self.apple = 'not %s' % appletype

o2 = pickle.loads(s)

print o2.apple

Основная идея состоит в том, что вы упаковываете свой класс в своего рода "троянского коня", где его реконструкция вызывает экземпляр различного класса от того, каково это первоначально было.

не имеет значения, что otherclass на стороне соления содержит. Все, что имеет значение, - то, что это существует на том же самом пути модуля как класс "назначения" - , рассол просто помещает строковое представление имени модуля в сериализованный поток.

Так, чтобы сломать, что происходит в вышеупомянутом коде подробно:

  • Мы регистрируем обычай, более придирчивый для myClass . Это может быть сделано с помощью copy_reg или __ reduce_ex __ функция.
  • , который заявляет Наш более придирчивый обычай, "солит это как случай otherclass " (который является куклой. Вы не делаете , нуждаются в "реальном" содержании otherclass на стороне соления, потому что все, что входит в рассол, является модулем/именем класса).
  • Мы солим объект и, "посылает его через провод", туда, где реальная версия otherclass существует.
  • На отдаленной стороне, otherclass иллюстрируется примерами с данными из кортежа, возвращенного таможенной функцией соления.

Питон может быть довольно сильным!

4
добавлено
@JohnY можно превратить нерассол класса в случай произвольного класса от unpickler' s пространство имен. Вы настраиваете myClass , чтобы не засолить как foomodule.myClass , и затем вы говорите foomodule.myClass = НЕ УТОЧНЕНО [' myClass'] перед называнием pickle.loads .
добавлено автор Borealid, источник
Это все очень опрятно, но как это отвечает на оригинальный вопрос?
добавлено автор John Y, источник

Я обнаружил решение это. Кажется, что проблема выполняет код в dict, препятствует тому, чтобы питон выяснил, где класс определяется. Решение состоит в том, чтобы создать пустой модуль, выполнить код в модуле, и затем добавить модуль к sys.modules, таким образом, питон знает об этом.

script = """
class myClass:
    def __init__(self):
        self.name = 'apple'
        self.color = 'green'
"""

import imp, sys

moduleName = 'custom'

module = imp.new_module(moduleName)

exec script in module.__dict__

sys.modules[moduleName] = module

Теперь возможно засолить и не засолить случай класса:

import pickle
a = module.myClass()
s = pickle.dumps(a)
b = pickle.loads(s)
3
добавлено
Python
Python
7 654 участник(ов)

Уютный чат для профессионалов, занимающихся поиском питоньих мудростей. Как не получить бан: https://t.me/ru_python/577926

Python beginners
Python beginners
4 449 участник(ов)

Вопросы про Python для чайников. Cпам и троллинг неприемлем. Не злоупотребляйте стикерами. Частозадаваемые вопросы: https://github.com/ru-python-beginners/faq/blob/master/README.md Статистика тут: https://grstats.me/chat/x4qym2k5uvfkr3al6at7

pro.python
pro.python
1 090 участник(ов)

Сообщество разработчиков под Python Создатель: @rodgelius

Rude Python
Rude Python
971 участник(ов)

Python без „девочек”, здесь матерятся и унижают Django. Not gay friendly. Правила: t.me/rudepython/114107 @rudepython | t.me/rudepython

rupython
rupython
509 участник(ов)

Группа создана с целью оперативного получения ответов на возникающие вопросы по разработке на яп python, смежные темы, а также человеческого общения. Приветствую!

Python-programming
Python-programming
266 участник(ов)

Чат группы вконтакте https://vk.com/python_community