Вы можете решить и реализовать способ, с помощью которого любой ранее невыбираемый тип выбирается и выбирается: см. Стандартный библиотечный модуль copy_reg (переименован в copyreg
в Python 3. *).
В сущности, вам нужно предоставить функцию, которая, учитывая экземпляр типа, сводит его к кортежу - с тем же протоколом, что и специальный метод reduce (кроме что специальный метод Reduce не принимает аргументов, поскольку при условии, что он вызывается непосредственно для объекта, а предоставляемая вами функция будет принимать этот объект в качестве единственного аргумента).
Как правило, возвращаемый вами кортеж имеет 2 элемента: вызываемый и кортеж аргументов для передачи ему. Вызываемый объект должен быть зарегистрирован как «безопасный конструктор» или эквивалентно иметь атрибут __safe_for_unpickling__
с истинным значением. Эти элементы будут засечены, и в момент разборки будет вызван вызываемый объект с заданными аргументами, и он должен вернуть неотобранный объект.
Например, предположим, что вы хотите просто выбрать модули по имени, так что удаление их просто означает их повторный импорт (т. Е. Для простоты предположим, что вам не нужны динамически модифицированные модули, вложенные пакеты и т. Д., Просто модули верхнего уровня). Тогда:
>>> import sys, pickle, copy_reg
>>> def savemodule(module):
... return __import__, (module.__name__,)
...
>>> copy_reg.pickle(type(sys), savemodule)
>>> s = pickle.dumps(sys)
>>> s
"c__builtin__\n__import__\np0\n(S'sys'\np1\ntp2\nRp3\n."
>>> z = pickle.loads(s)
>>> z
<module 'sys' (built-in)>
Я использую старомодную форму pickle ASCII, так что s
, строку, содержащую pickle, легко исследовать: она дает команду unpickling вызвать встроенную функцию импорта со строкой sys
в качестве единственного аргумента. И z
показывает, что это действительно возвращает нам встроенный модуль sys
в результате расслоения, как требуется.
Теперь вам придется сделать вещи немного более сложными, чем просто __import__
(вам придется иметь дело с сохранением и восстановлением динамических изменений, перемещаться по вложенному пространству имен и т. Д.), И, таким образом, вам придется также вызовите copy_reg.constructor
(передавая в качестве аргумента вашу собственную функцию, которая выполняет эту работу) перед вами copy_reg
функцией сохранения модуля, которая возвращает вашу другую функцию (и, если в отдельном прогоне, также перед тем, как вы отрежете те соленья, которые вы сделали с помощью указанная функция). Но я надеюсь, что эти простые случаи помогают показать, что в этом нет ничего особенного, что вообще "по сути" сложно! -)