2010-04-13 6 views
5

Есть ли способ определить значение класса?Определение травления класса

Что я хотел бы сделать, это разбить определение (которое может создаваться динамически), а затем отправить его по TCP-соединению, чтобы экземпляр мог быть создан на другом конце.

Я понимаю, что могут существовать зависимости, такие как модули и глобальные переменные, на которые полагается класс. Я хотел бы также связать их в процессе травления, но меня не интересует автоматическое обнаружение зависимостей, потому что это нормально, если он обязан указать их.

+0

Я нашел это, который соленья весь штат переводчика: http://dev.pocoo.org/hg/sandbox/file/tip/pshell.py Определения классов, по-видимому, также маринуются ... – Giorgio

ответ

2

Увы, не напрямую. Вы можете отправить строчную форму оператора class или форму байт-кода и «перегрузить» ее с помощью exec на принимающей стороне.

+0

Вы имеете в виду просто отправку файлов .py или .pyc, содержащих инструкцию класса? – Giorgio

+1

@Giorgio, вам необязательно отправлять _all_ файла '.py' или' .pyc', только источник самого класса (как определено http://docs.python.org/library/inspect .html? # inspect.getsource) или его 'compile'd. –

1

В документации очень хорошо объясняется, что можно и нельзя травить, и почему это так.

http://docs.python.org/library/pickle.html#what-can-be-pickled-and-unpickled

В принципе, если класс или модуль ввоза по имени, когда он получает unpickled, он должен работать, если вы не планируете изменить ваше определение класса теперь и когда вы unpickle его. В определении класса ниже указывается только имя класса «Тест» и имя метода «mymethod». Если вы определитесь с определением класса, измените определение так, чтобы attr было другим значением, а mymethod делает что-то совершенно другое, маринование подберет новое определение.

class Test(object): 
    attr = 5 

    def mymethod(self, arg): 
     return arg 
1

Если вы используете dill, это позволяет лечить __main__, как если бы это был модуль питона (по большей части). Следовательно, вы можете сериализовать интерактивно определенные классы и т. П. dill также (по умолчанию) может передать определение класса как часть рассола.

>>> class MyTest(object): 
... def foo(self, x): 
...  return self.x * x 
... x = 4 
... 
>>> f = MyTest() 
>>> import dill 
>>> 
>>> with open('test.pkl', 'wb') as s: 
... dill.dump(f, s) 
... 
>>> 

Затем выключите интерпретатор, и отправить файл test.pkl через TCP. На вашем удаленном компьютере теперь вы можете получить экземпляр класса.

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill 
>>> with open('test.pkl', 'rb') as s: 
... f = dill.load(s) 
... 
>>> f 
<__main__.MyTest object at 0x1069348d0> 
>>> f.x 
4 
>>> f.foo(2) 
8 
>>>    

Но как получить определение класса? Так что это не совсем то, что вы хотели. Однако следующее.

>>> class MyTest2(object): 
... def bar(self, x): 
...  return x*x + self.x 
... x = 1 
... 
>>> import dill 
>>> with open('test2.pkl', 'wb') as s: 
... dill.dump(MyTest2, s) 
... 
>>> 

После отправки файла ... вы можете получить определение класса.

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill 
>>> with open('test2.pkl', 'rb') as s: 
... MyTest2 = dill.load(s) 
... 
>>> print dill.source.getsource(MyTest2) 
class MyTest2(object): 
    def bar(self, x): 
    return x*x + self.x 
    x = 1 

>>> f = MyTest2() 
>>> f.x 
1 
>>> f.bar(4) 
17 

Так, в dill, есть dill.source, и что есть методы, которые могут обнаруживать зависимости от функций и классов, и принимать их вместе с рассол (по большей части).

>>> def foo(x): 
... return x*x 
... 
>>> class Bar(object): 
... def zap(self, x): 
...  return foo(x) * self.x 
... x = 3 
... 
>>> print dill.source.importable(Bar.zap, source=True) 
def foo(x): 
    return x*x 
def zap(self, x): 
    return foo(x) * self.x 

Так что это не «совершенный» (или, возможно, не то, что ожидалось) ... но это не сериализации код динамически построенного метода и его зависимостей. Вы просто не получите остальную часть класса, но в этом случае остальная часть класса не нужна.

Если вы хотите получить все, вы можете просто рассолить весь сеанс.

>>> import dill 
>>> def foo(x): 
... return x*x 
... 
>>> class Blah(object): 
... def bar(self, x): 
...  self.x = (lambda x:foo(x)+self.x)(x) 
... x = 2 
... 
>>> b = Blah() 
>>> b.x 
2 
>>> b.bar(3) 
>>> b.x 
11 
>>> dill.dump_session('foo.pkl') 
>>> 

Затем на удаленной машине ...

Python 2.7.9 (default, Dec 11 2014, 01:21:43) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill 
>>> dill.load_session('foo.pkl') 
>>> b.x 
11 
>>> b.bar(2) 
>>> b.x 
15 
>>> foo(3) 
9 

И наконец, если вы хотите, транспорт, чтобы быть «сделано» прозрачно для вас, вы можете использовать pathos.pp или ppft, которые обеспечивают возможность отгружать объектов на второй сервер питона (на удаленной машине) или питона обработать. Они используют dill под капотом и просто передают код через провод.

>>> class More(object): 
... def squared(self, x): 
...  return x*x 
... 
>>> import pathos 
>>> 
>>> p = pathos.pp.ParallelPythonPool(servers=('localhost,1234',)) 
>>> 
>>> m = More() 
>>> p.map(m.squared, range(5)) 
[0, 1, 4, 9, 16] 

servers аргумент является необязательным, и вот только при подключении к локальной машине на порту 1234 ... но если вы используете имя удаленной машины и порт вместо (или вместе), вы выпалить в удаленная машина - «без усилий».

Получить dill, pathos и ppft здесь: https://github.com/uqfoundation