variable the storing predefined name from current called another python variables share

from - a predefined python variable, storing the current module name, is called:



¿Cómo compartir variables a través de scripts en python? (9)

En su ejemplo, el primer script se ejecuta hasta su finalización, y luego el segundo script se ejecuta. Eso significa que necesitas algún tipo de estado persistente. Otras respuestas han sugerido el uso de archivos de texto o el módulo pickle de Python. Personalmente soy perezoso, y no usaría un archivo de texto cuando podría usar pickle ; ¿Por qué debo escribir un analizador para analizar mi propio formato de archivo de texto?

En lugar de pickle , también puede usar el módulo json para almacenarlo como JSON. Esto podría ser preferible si desea compartir los datos con programas que no sean de Python, ya que JSON es un estándar simple y común. Si tu Python no tiene json , obtén simplejson json .

Si sus necesidades van más allá de pickle o json , digamos que en realidad desea tener dos programas de Python ejecutándose al mismo tiempo y actualizando las variables de estado persistentes en tiempo real, le sugiero que use la SQLite datos SQLite . Utilice un ORM para abstraer la base de datos, y es muy fácil. Para SQLite y Python, recomiendo Autumn ORM .

Lo siguiente no funciona

one.py

import shared shared.value = ''Hello'' raw_input(''A cheap way to keep process alive..'')

dos.py

import shared print shared.value

Ejecutar en dos líneas de comando como:

>>python one.py >>python two.py

(El segundo recibe un error de atributo, con razón).

¿Hay alguna forma de lograr esto, es decir, compartir una variable entre dos scripts?


Es necesario almacenar la variable en algún tipo de archivo persistente. Hay varios módulos para hacer esto, dependiendo de su necesidad exacta.

El módulo pickle y cPickle puede guardar y cargar la mayoría de los objetos de Python en un archivo.

El módulo de almacenamiento puede almacenar objetos de python en una estructura similar a un diccionario (utilizando pickle detrás de escena).

Los módulos dbm / bsddb / dbhash / gdm pueden almacenar variables de cadena en una estructura similar a un diccionario.

El módulo sqlite3 puede almacenar datos en una base de datos SQL ligera.

El mayor problema con la mayoría de estos es que no están sincronizados a través de diferentes procesos: si un proceso lee un valor mientras otro escribe en el almacén de datos, es posible que obtenga datos incorrectos o que se dañen. Para solucionar esto, deberá escribir su propio mecanismo de bloqueo de archivos o usar una base de datos completa.


Espero que esté bien anotar mis notas sobre este tema aquí.

En primer lugar, aprecio mucho el ejemplo en el OP, porque ahí es también donde comencé, aunque me hizo pensar que shared era un módulo Python incorporado, hasta que encontré un ejemplo completo en [Tutor] Variables globales entre Módulos ?? .

Sin embargo, cuando busqué "compartir variables entre scripts" (o procesos), además del caso cuando un script de Python necesita usar variables definidas en otros archivos de origen de Python (pero no necesariamente procesos en ejecución), me topé con otros dos casos de uso. :

  • Un script se divide en varios procesos secundarios, que luego se ejecutan en paralelo (posiblemente en varios procesadores) en la misma PC
  • Un script genera otros procesos secundarios, que luego se ejecutan en paralelo (posiblemente en varios procesadores) en la misma PC

Como tal, la mayoría de los éxitos relacionados con "variables compartidas" y "comunicación entre procesos" (IPC) tratan casos como estos dos; sin embargo, en ambos casos se puede observar un "padre", al cual los "hijos" usualmente tienen una referencia.

Sin embargo, lo que me interesa es ejecutar múltiples invocaciones del mismo script, ejecutarse de forma independiente y compartir datos entre ellos (como en Python: cómo compartir una instancia de objeto a través de múltiples invocaciones de un script ), en una instancia única / única modo. Ese tipo de problema no se resuelve realmente en los dos casos anteriores, sino que se reduce esencialmente al ejemplo en OP (compartir variables en dos scripts).

Ahora, cuando se trata de este problema en Perl, hay IPC::Shareable ; que "le permite vincular una variable a la memoria compartida", utilizando "un número entero o una cadena de 4 caracteres [1] que sirve como un identificador común para los datos en todo el espacio de proceso". Por lo tanto, no hay archivos temporales ni configuraciones de red, lo que me parece excelente para mi caso de uso; Así que estaba buscando lo mismo en Python.

Sin embargo, como responde la respuesta de @Drewfer, señala: " No podrá hacer lo que quiera sin almacenar la información en un lugar externo a las dos instancias del intérprete "; o en otras palabras: o tienes que usar una configuración de red / socket - o tienes que usar archivos temporales (ergo, no hay RAM compartida para " sesiones de python totalmente separadas ").

Ahora, incluso con estas consideraciones, es un poco difícil encontrar ejemplos de trabajo (a excepción de pickle ), también en los documentos para mmap y multiprocessing . He logrado encontrar algunos otros ejemplos, que también describen algunos escollos que los documentos no mencionan:

  • Uso de mmap : código de trabajo en dos scripts diferentes en Compartir datos de Python entre procesos usando mmap | el blog de schmichael
    • Demuestra cómo ambos scripts cambian el valor compartido
    • Tenga en cuenta que aquí se crea un archivo temporal como almacenamiento para los datos guardados: mmap es solo una interfaz especial para acceder a este archivo temporal
  • Uso de multiprocessing : código de trabajo en:
    • Python multiprocessing RemoteManager bajo multiprocessing.Process : ejemplo funcional de SyncManager (a través de manager.start() ) con Queue compartida; Escrituras de servidor (s), lectura de clientes (datos compartidos)
    • ¿Comparación del módulo multiprocesamiento y pyro? - ejemplo de trabajo de BaseManager (a través de server.serve_forever() ) con clase personalizada compartida; Servidor escribe, cliente lee y escribe
    • Cómo sincronizar un dict de Python con multiprocesamiento : esta respuesta tiene una gran explicación de multiprocessing trampas del multiprocessing , y es un ejemplo funcional de SyncManager (a través de manager.start() ) con dict compartido; El servidor no hace nada, el cliente lee y escribe.

Gracias a estos ejemplos, se me ocurrió un ejemplo, que esencialmente hace lo mismo que el ejemplo mmap , con enfoques del ejemplo " sincronizar un BaseManager Python ": usar BaseManager (a través de manager.start() través de la dirección de ruta de archivo) con una dirección compartida. lista; Tanto el servidor como el cliente leen y escriben (pegados a continuación). Tenga en cuenta que:

  • multiprocessing gestores de multiprocessing se pueden iniciar a través de manager.start() o server.serve_forever()
    • serve_forever() bloquea - start() no lo hace
    • Hay una función de registro automático en el multiprocessing : parece funcionar bien con los procesos de start() ed, pero parece ignorar los que serve_forever()
  • La especificación de la dirección en el multiprocessing puede ser IP (socket) o archivo temporal (¿posiblemente una tubería?) Ruta; en documentos de multiprocessing :
    • La mayoría de los ejemplos utilizan multiprocessing.Manager() : esta es solo una función ( no una SyncManager clase) que devuelve un SyncManager , que es una subclase especial de BaseManager ; y usa start() , pero no para IPC entre scripts ejecutados de forma independiente; Aquí se utiliza una ruta de archivo
    • Algunos otros ejemplos de enfoque de serve_forever() para IPC entre scripts ejecutados de forma independiente; Aquí se utiliza la dirección IP / socket
    • Si no se especifica una dirección, entonces se usa automáticamente una ruta de archivo temporal (vea 16.6.2.12. Registrando un ejemplo de cómo ver esto)

Además de todos los escollos en la publicación " sincronizar un dict de python ", hay otros adicionales en el caso de una lista. Ese post notas:

Todas las manipulaciones del dict deben realizarse con métodos y no con asignaciones de dict (syncdict ["blast"] = 2 fallará miserablemente debido a la forma en que el multiprocesamiento comparte objetos personalizados)

La solución para obtener y configurar dict[''key''] , es el uso de los métodos públicos de dict get y update . El problema es que no existen métodos públicos como alternativa para la list[index] ; por lo tanto, para una lista compartida, además tenemos que registrar los métodos __getitem__ y __setitem__ (que son privados para la list ) como están exposed , lo que significa que también tenemos que volver a registrar todos los métodos públicos para la list también :/

Bueno, creo que esas fueron las cosas más críticas; estos son los dos scripts: solo se pueden ejecutar en terminales separados (servidor primero); nota desarrollada en Linux con Python 2.7:

a.py (servidor):

import multiprocessing import multiprocessing.managers import logging logger = multiprocessing.log_to_stderr() logger.setLevel(logging.INFO) class MyListManager(multiprocessing.managers.BaseManager): pass syncarr = [] def get_arr(): return syncarr def main(): # print dir([]) # cannot do `exposed = dir([])`!! manually: MyListManager.register("syncarr", get_arr, exposed=[''__getitem__'', ''__setitem__'', ''__str__'', ''append'', ''count'', ''extend'', ''index'', ''insert'', ''pop'', ''remove'', ''reverse'', ''sort'']) manager = MyListManager(address=(''/tmp/mypipe''), authkey='''') manager.start() # we don''t use the same name as `syncarr` here (although we could); # just to see that `syncarr_tmp` is actually <AutoProxy[syncarr] object> # so we also have to expose `__str__` method in order to print its list values! syncarr_tmp = manager.syncarr() print("syncarr (master):", syncarr, "syncarr_tmp:", syncarr_tmp) print("syncarr initial:", syncarr_tmp.__str__()) syncarr_tmp.append(140) syncarr_tmp.append("hello") print("syncarr set:", str(syncarr_tmp)) raw_input(''Now run b.py and press ENTER'') print print ''Changing [0]'' syncarr_tmp.__setitem__(0, 250) print ''Changing [1]'' syncarr_tmp.__setitem__(1, "foo") new_i = raw_input(''Enter a new int value for [0]: '') syncarr_tmp.__setitem__(0, int(new_i)) raw_input("Press any key (NOT Ctrl-C!) to kill server (but kill client first)".center(50, "-")) manager.shutdown() if __name__ == ''__main__'': main()

b.py (cliente)

import time import multiprocessing import multiprocessing.managers import logging logger = multiprocessing.log_to_stderr() logger.setLevel(logging.INFO) class MyListManager(multiprocessing.managers.BaseManager): pass MyListManager.register("syncarr") def main(): manager = MyListManager(address=(''/tmp/mypipe''), authkey='''') manager.connect() syncarr = manager.syncarr() print "arr = %s" % (dir(syncarr)) # note here we need not bother with __str__ # syncarr can be printed as a list without a problem: print "List at start:", syncarr print "Changing from client" syncarr.append(30) print "List now:", syncarr o0 = None o1 = None while 1: new_0 = syncarr.__getitem__(0) # syncarr[0] new_1 = syncarr.__getitem__(1) # syncarr[1] if o0 != new_0 or o1 != new_1: print ''o0: %s => %s'' % (str(o0), str(new_0)) print ''o1: %s => %s'' % (str(o1), str(new_1)) print "List is:", syncarr print ''Press Ctrl-C to exit'' o0 = new_0 o1 = new_1 time.sleep(1) if __name__ == ''__main__'': main()

Como observación final, en Linux /tmp/mypipe se crea, pero tiene 0 bytes y tiene los atributos srwxr-xr-x (para un socket); Supongo que esto me hace feliz, ya que no tengo que preocuparme por los puertos de red, ni por los archivos temporales como tales :)

Otras preguntas relacionadas:


Lo que intenta hacer aquí (almacenar un estado compartido en un módulo de Python a través de intérpretes de Python separados) no funcionará.

Un valor en un módulo puede ser actualizado por un módulo y luego leído por otro módulo, pero esto debe estar dentro del mismo intérprete de Python. Lo que parece que está haciendo aquí es en realidad una especie de comunicación entre procesos; Esto podría lograrse mediante la comunicación de socket entre los dos procesos, pero es significativamente menos trivial de lo que se espera que funcione aquí.


No podrá hacer lo que quiera sin almacenar la información en un lugar externo a las dos instancias del intérprete.
Si solo desea las variables simples, puede volcar fácilmente un dict de python en un archivo con el módulo pickle en el script uno y luego volver a cargarlo en el script dos. Ejemplo:

one.py

import pickle shared = {"Foo":"Bar", "Parrot":"Dead"} fp = open("shared.pkl","w") pickle.dump(shared, fp)

dos.py

import pickle fp = open("shared.pkl") shared = pickle.load(fp) print shared["Foo"]


Puede utilizar el archivo mmap relativo simple. puede utilizar el shared.py para almacenar las constantes comunes. El siguiente código funcionará en diferentes intérpretes de Python / scripts / procesos

shared.py:

MMAP_SIZE = 16*1024 MMAP_NAME = ''Global//SHARED_MMAP_NAME''

* El "Global" es la sintaxis de Windows para los nombres globales

one.py:

from shared import MMAP_SIZE,MMAP_NAME def write_to_mmap(): map_file = mmap.mmap(-1,MMAP_SIZE,tagname=MMAP_NAME,access=mmap.ACCESS_WRITE) map_file.seek(0) map_file.write(''hello/n'') ret = map_file.flush() != 0 if sys.platform.startswith(''win''): assert(ret != 0) else: assert(ret == 0)

dos.py:

from shared import MMAP_SIZE,MMAP_NAME def read_from_mmap(): map_file = mmap.mmap(-1,MMAP_SIZE,tagname=MMAP_NAME,access=mmap.ACCESS_READ) map_file.seek(0) data = map_file.readline().rstrip(''/n'') map_file.close() print data

* Este código fue escrito para Windows, Linux puede necesitar pequeños ajustes

más información en - https://docs.python.org/2/library/mmap.html


Te aconsejo que uses el módulo multiprocessing . No puede ejecutar dos scripts desde la línea de comandos, pero puede hacer que dos procesos separados se hablen fácilmente.

De los ejemplos del doc.

from multiprocessing import Process, Queue def f(q): q.put([42, None, ''hello'']) if __name__ == ''__main__'': q = Queue() p = Process(target=f, args=(q,)) p.start() print q.get() # prints "[42, None, ''hello'']" p.join()


Utilizar archivos de texto o variables de entorno. Ya que los dos se ejecutan por separado, realmente no puedes hacer lo que estás tratando de hacer.


sudo apt-get install memcached python-memcache

one.py

import memcache shared = memcache.Client([''127.0.0.1:11211''], debug=0) shared.set(''Value'', ''Hello'')

dos.py

import memcache shared = memcache.Client([''127.0.0.1:11211''], debug=0) print shared.get(''Value'')