Есть ли простой способ замариновать функцию python (или иным образом сериализовать ее код)?
Я пытаюсь передать функцию через сетевое соединение (через asyncore). Есть ли простой способ сериализовать функцию python (которая, по крайней мере, в этом случае не будет иметь побочных эффектов) для такой передачи?
в идеале я хотел бы иметь пару функций, подобных этим:
def transmit(func):
obj = pickle.dumps(func)
[send obj across the network]
def receive():
[receive obj from the network]
func = pickle.loads(s)
func()
8 ответов:
вы можете сериализовать байт-код функции, а затем восстановить его на вызывающем устройстве. Элемент маршал модуль может использоваться для сериализации объектов кода,которые затем могут быть собраны в функцию. т. е.:
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.
Если функция ссылается на глобалы (включая импортированные модули, другие функции и т. д.), которые вам нужно забрать, вам также нужно сериализовать их или воссоздать их на удаленной стороне. Мой пример просто дает ему глобальное пространство имен удаленного процесса.
вам, вероятно, нужно будет сделать немного больше, чтобы поддерживать более сложные случаи, такие как закрытие или функции генератора.
проверить укроп, который расширяет библиотеку pickle Python для поддержки большего разнообразия типов, включая функции:
>>> import dill as pickle >>> def f(x): return x + 1 ... >>> g = pickle.dumps(f) >>> f(1) 2 >>> pickle.loads(g)(1) 2
Он также поддерживает ссылки на объекты в закрытии функции:
>>> def plusTwo(x): return f(f(x)) ... >>> pickle.loads(pickle.dumps(plusTwo))(1) 3
Pyro способен сделать это для вас.
самый простой способ, вероятно,
inspect.getsource(object)
(см. модуль проверить), которая возвращает строку с исходным кодом для функции или метода.
все зависит от того, генерируете ли вы функцию во время выполнения или нет:
если вы это сделаете -
inspect.getsource(object)
не будет работать для динамически генерируемых функций, поскольку он получает источник объекта от.py
файл, поэтому в качестве источника могут быть получены только функции, определенные до выполнения.и если ваши функции все равно помещаются в файлы, почему бы не дать им доступ к приемнику и не передавать только имена модулей и функций.
единственное решение для динамического создания функции, которые я могу придумать, это построить функцию как строку перед передачей, передать источник, а затем
eval()
это на стороне приемника.Edit: the
marshal
решение выглядит также довольно умным, не знал, что вы можете сериализовать что-то другое thatn встроенные
на
cloud
пакет (pip install cloud) может мариновать произвольный код, включая зависимости. См.https://stackoverflow.com/a/16891169/1264797.
основные функции, используемые для этого модуля, охватывают ваш запрос, плюс вы получаете лучшее сжатие по проводу; см. инструктивный исходный код:
y_serial.py модуль:: склад Python объектов с SQLite
"Serialization + persistance:: в нескольких строках кода сжимайте и аннотируйте объекты Python в SQLite; затем позже извлекайте их хронологически по ключевым словам без какого-либо SQL. Самый полезный" стандартный " модуль для базы данных для хранения без схемы данные."