Как выбрать функции / классы, определенные в __main__ (python)
Я хотел бы иметь возможность выбирать функцию или класс изнутри __main__, с очевидной проблемой (упомянутой в других статьях), что выбранная функция / класс находится в пространстве имен __main__, и удаление в другом скрипте / модуле завершится неудачно.
У меня есть следующее решение, которое работает, есть ли причина, по которой это не должно быть сделано?
Следующее находится в myscript.py:
import myscript
import pickle
if __name__ == "__main__":
print pickle.dumps(myscript.myclass())
else:
class myclass:
pass
редактирование: удаление будет выполнено в скрипте / модуле, который имеет доступ к myscript.py и может сделать import myscript
, Цель состоит в том, чтобы использовать решение, подобное параллельному python, для удаленного вызова функций и иметь возможность написать короткий автономный скрипт, содержащий функции / классы, к которым можно получить удаленный доступ.
3 ответа
Пикл, кажется, смотрит на основную сферу определения классов и функций. Внутри модуля, из которого вы извлекаете, попробуйте это:
import myscript
import __main__
__main__.myclass = myscript.myclass
#unpickle anywhere after this
Вы можете лучше обрабатывать глобальные объекты, импортируя __main__
и с использованием методов, доступных в этом модуле. Это то, что делает укроп, чтобы сериализовать почти все в Python. В основном, когда укроп сериализует интерактивно определенную функцию, он использует некоторую манипуляцию именами на __main__
как на стороне сериализации и десериализации, что делает __main__
действительный модуль.
>>> import dill
>>>
>>> def bar(x):
... return foo(x) + x
...
>>> def foo(x):
... return x**2
...
>>> bar(3)
12
>>>
>>> _bar = dill.loads(dill.dumps(bar))
>>> _bar(3)
12
На самом деле, укроп регистрирует свои виды в pickle
реестра, так что если у вас есть код черного ящика, который использует pickle
и вы не можете его отредактировать, тогда просто импортирование укропа может волшебным образом заставить его работать без мартовских патчей стороннего кода.
Или, если вы хотите, чтобы весь сеанс переводчика передавался как "образ питона", укроп тоже может это сделать.
>>> # continuing from above
>>> dill.dump_session('foobar.pkl')
>>>
>>> ^D
dude@sakurai>$ python
Python 2.7.5 (default, Sep 30 2013, 20:15:49)
[GCC 4.2.1 (Apple Inc. build 5566)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> dill.load_session('foobar.pkl')
>>> _bar(3)
12
Вы можете легко отправить образ через ssh на другой компьютер и начать с того места, на котором остановились, при условии совместимости версий pickle и обычных предупреждений об изменении Python и установке.
Я на самом деле использую укроп для сериализации объектов и отправки их через параллельные ресурсы с параллельным питоном, многопроцессорностью и mpi4py. Я сворачиваю их удобно в пафосный пакет (и pyina для MPI), который обеспечивает униформу map
Интерфейс для различных параллельных обработчиков пакетной обработки.
>>> # continued from above
>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> Pool(4).map(foo, range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>>
>>> from pyina.launchers import MpiPool
>>> MpiPool(4).map(foo, range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Существуют также неблокирующие и итеративные карты, а также непараллельные соединения каналов. У меня также есть модуль пафоса для pp
однако он несколько нестабилен для функций, определенных в __main__
, Я работаю над улучшением этого. Если хотите, разветвите код на github и помогите сделать pp
лучше для функций, определенных в __main__
, Причина pp
не мариновать хорошо, что pp
выполняет сериализацию, используя временные файловые объекты и читая историю сеанса интерпретатора... поэтому он не сериализует объекты так же, как это делает многопроцессорная обработка или mpi4py. У меня модуль укропа dill.source
который плавно делает тот же тип травления, что pp
использует, но это довольно новое.
Если вы пытаетесь засолить что-то, чтобы вы могли использовать его где-то еще, отдельно от test_script
, это не сработает, потому что pickle (очевидно) просто пытается загрузить функцию из модуля. Вот пример:
test_script.py
def my_awesome_function(x, y, z):
return x + y + z
picklescript.py
import pickle
import test_script
with open("awesome.pickle", "wb") as f:
pickle.dump(test_script.my_awesome_function, f)
Если вы бежите python picklescript.py
затем измените имя файла test_script
, когда вы пытаетесь загрузить функцию, она потерпит неудачу. например
Запуск этого:
import pickle
with open("awesome.pickle", "rb") as f:
pickle.load(f)
Даст вам следующую трассировку:
Traceback (most recent call last):
File "load_pickle.py", line 3, in <module>
pickle.load(f)
File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pickle.py", line 1124, in find_class
__import__(module)
ImportError: No module named test_script