Вы можете сериализовать байт-код функции, а затем восстановить его в вызывающей стороне. Модуль маршалинга может использоваться для сериализации объектов кода, которые затем могут быть повторно собраны в функцию. то есть:
import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.func_code)
Затем в удаленном процессе (после передачи code_string):
import marshal, types
code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")
func(10) # gives 100
Несколько предостережений:
Формат маршала (любой байт-код Python в этом отношении) может быть несовместим между основными версиями Python.
Будет работать только для реализации cpython.
Если функция ссылается на глобальные объекты (включая импортированные модули, другие функции и т. Д.), Которые вам нужно подобрать, вам также необходимо сериализовать их или воссоздать их на удаленной стороне. В моем примере просто указано глобальное пространство имен удаленного процесса.
Вероятно, вам нужно будет сделать немного больше для поддержки более сложных случаев, таких как замыкания или функции генератора.
marshal
модуль для сериализации словаря словарей, инициализированных какdefaultdict(lambda : defaultdict(int))
. Но возвращает ошибкуValueError: unmarshallable object
. Обратите внимание: я использую python2.7. Любая идея? Спасибоfoo.func_code
вызываетAttributeError
. Есть ли другой способ получить код функции?Обратите внимание на Dill , который расширяет библиотеку pickle Python для поддержки большего количества типов, включая функции:
Он также поддерживает ссылки на объекты в закрытии функции:
источник
Поджигатель может сделать это за вас .
источник
Самый простой способ - это, вероятно
inspect.getsource(object)
(см. Модуль inspect ), который возвращает строку с исходным кодом для функции или метода.источник
Все зависит от того, генерируете ли вы функцию во время выполнения или нет:
Если вы это сделаете -
inspect.getsource(object)
не будет работать для динамически генерируемых функций, поскольку он получает источник объекта из.py
файла, поэтому только функции, определенные до выполнения, могут быть извлечены в качестве источника.И если ваши функции все равно помещаются в файлы, почему бы не предоставить доступ к ним получателю и передать только имена модулей и функций.
Единственное решение для динамически создаваемых функций, которое я могу придумать, - это создать функцию в виде строки перед передачей, источником передачи, а затем
eval()
на стороне приемника.Изменить:
marshal
решение выглядит также довольно умным, не знал, что вы можете сериализовать что-то другое, встроенноеисточник
cloud
Пакет (ПГИ установить облако) может законсервировать произвольный код, в том числе зависимостей. См. Https://stackoverflow.com/a/16891169/1264797 .источник
Сейчас
источник
Ты можешь сделать это:
Теперь
transmit(fn_generator())
будет отправлено фактическое определениеfn(x,y)
вместо ссылки на имя модуля.Вы можете использовать тот же прием для отправки классов по сети.
источник
Основные функции, используемые для этого модуля, охватывают ваш запрос, плюс вы получаете наилучшее сжатие по сети; см. поучительный исходный код:
y_serial.py module :: складские объекты Python с SQLite
«Сериализация + постоянство :: в нескольких строках кода сжимайте и аннотируйте объекты Python в SQLite; а затем извлекайте их в хронологическом порядке по ключевым словам без какого-либо SQL. Самый полезный« стандартный »модуль для базы данных для хранения данных без схемы».
http://yserial.sourceforge.net
источник
Cloudpickle , вероятно, то, что вы ищете. Облако описывается следующим образом:
Пример использования:
источник
Вот вспомогательный класс, который вы можете использовать для обертывания функций, чтобы сделать их доступными для выбора. Уже упомянутые предостережения
marshal
применимы, но по возможности стараемся использовать рассол. Не прилагается никаких усилий для сохранения глобальных объектов или замыканий при сериализации.источник