web-dev-qa-db-fra.com

Comment partager des variables à travers les scripts à Python?

Ce qui suit ne fonctionne pas

one.py

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

deux.pypy

import shared
print shared.value

exécuter sur deux lignes de commande comme suit:

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

(La seconde obtient une erreur d'attribut, à juste titre).

Existe-t-il un moyen d'accomplir cela, c'est-à-dire partager une variable entre deux scripts?

22
azarias

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')

deux.pypy

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

Ce que vous essayez de faire ici (stockez un état partagé dans un Python module sur séparé python interprètes) ne fonctionnera pas.

Une valeur dans un module peut être mise à jour par un module, puis lue par un autre module, mais cela doit être dans le même fichier Python INTERPRÈTE. Qu'est-ce que vous semblez faire ici est en fait une sorte d'interprocession Communication; cela pourrait être accompli via une communication de socket entre les deux processus, mais il est significativement moins trivial que ce que vous attendez de travailler ici.

6
Gabriel Reid

vous pouvez utiliser le fichier MMAP simple relativement. Vous pouvez utiliser le Shared.py pour stocker les constantes communes. Le code suivant fonctionnera sur différents python interprètes\scripts\processus

partagé.py:

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

* Le "global" est la syntaxe Windows pour les noms mondiaux

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)                                                                      

deux.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                                                                  

* Ce code a été écrit pour Windows, Linux peut avoir besoin de petits ajustements

plus d'infos à - https://docs.python.org/2/library/mmap.html

5
AmitE

Je vous conseillerais d'utiliser le module multiprocessing . Vous ne pouvez pas exécuter deux scripts de la ligne de commande, mais vous pouvez avoir deux processus distincts se parler facilement.

Des exemples du 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()
4
UsAaR33

Vous devez stocker la variable dans une sorte de fichier persistant. Il existe plusieurs modules pour le faire, en fonction de votre besoin exact.

Le module cornichon et cpickle peut enregistrer et charger la plupart python objets à fichier.

Le module d'étagère peut stocker python objets dans une structure en forme de dictionnaire (en utilisant le cornichement dans les coulisses).

Les modules DBM/BSDDB/DBHASH/GDM peuvent stocker des variables de chaîne dans une structure de type dictionnaire.

Le module SQLITE3 peut stocker des données dans une base de données SQL légère.

Le plus gros problème de la plupart d'entre eux est qu'ils ne sont pas synchronisés sur différents processus - si un processus lit une valeur tandis qu'un autre écrit dans le magasin de données, vous pouvez obtenir des données incorrectes ou une corruption de données. Pour vous rond, vous devrez écrire votre propre mécanisme de verrouillage de fichiers ou utiliser une base de données complète.

3
Dave Kirby

Utilisez des fichiers texte ou des variables d'environnement. Depuis les deux coureurs séparément, vous ne pouvez pas vraiment faire ce que vous essayez de faire.

1
David Brunelle

Dans votre exemple, le premier script passe à l'achèvement, puis le deuxième script fonctionne. Cela signifie que vous avez besoin d'une sorte d'état persistant. D'autres réponses ont suggéré d'utiliser des fichiers texte ou du module de pickle de Python. Personnellement, je suis paresseux, et je n'utiliserais pas de fichier texte lorsque je pourrais utiliser pickle; Pourquoi devrais-je écrire un analyseur pour analyser mon propre format de fichier texte?

Au lieu de pickle, vous pouvez également utiliser le module json pour la stocker en tant que JSON. Cela pourrait être préférable si vous souhaitez partager les données aux programmes non python, car JSON est une norme simple et commune. Si votre Python n'a pas json, obtenez-vous SimpleJson .

Si vos besoins vont au-delà de pickle ou json - dites que vous voulez réellement avoir deux Python programmes exécutant en même temps et mettre à jour les variables d'état persistantes dans Temps réel - Je vous suggère d'utiliser la base de données SQLite . Utilisez un orj pour résumer la base de données, et c'est super facile. Pour SQLite et Python, je recommande automne orm .

1
steveha

En utilisant Redis pour partager une variable dynamique:

script_one.py

from redis import Redis
from time import sleep

cli = Redis('localhost')
shared_var = 1

while True:
   cli.set('share_place', shared_var)
   shared_var += 1
   sleep(1)

Exécution script_one dans un terminal (processus):

$ python script_one.py

script_two.py

from time import sleep
from redis import Redis

cli = Redis('localhost')

while True:
    print(int(cli.get('share_place')))
    sleep(1)

Exécution script_two dans un autre terminal (un autre processus):

$ python script_two.py

Dehors:

1
2
3
4
5
...

Dépendances:

$ pip install redis
$ apt-get install redis-server
0
Benyamin Jafari

Vous pouvez également résoudre ce problème en faisant la variable comme mondiale.

python first.pypy

class Temp:
    def __init__(self):
        self.first = None

global var1
var1 = Temp()
var1.first = 1
print(var1.first)

python second.pypy

import first as One
print(One.var1.first)
0
Aniket Babhulkar

Si vous voulez lire et modifier des données partagées entre 2 scripts qui fonctionnent séparément, une bonne solution serait de tirer parti du module multiprocession python et Utilisez A Tuyau () ou une file d'attente () (voir Différences ICI ). De cette façon, vous obtenez des scripts synchronisés et évitez les problèmes concernant la concurrence et les variables globales (comme ce qui se passe si les deux scripts veulent modifier une variable en même temps).

La meilleure partie de l'utilisation de tuyaux/files d'attente est que vous pouvez passer des objets python à travers eux.

Il existe également des méthodes pour éviter d'attendre des données s'il n'y a pas encore été passé ( file d'attente.empty () et Pipeconn.poll () )] ==).

Voir un exemple d'utilisation de la file d'attente () ci-dessous:

    # main.py
    from multiprocessing import Process, Queue
    from stage1 import Stage1
    from stage2 import Stage2


    s1= Stage1()
    s2= Stage2()

    # S1 to S2 communication
    queueS1 = Queue()  # s1.stage1() writes to queueS1

    # S2 to S1 communication
    queueS2 = Queue()  # s2.stage2() writes to queueS2

    # start s2 as another process
    s2 = Process(target=s2.stage2, args=(queueS1, queueS2))
    s2.daemon = True
    s2.start()     # Launch the stage2 process

    s1.stage1(queueS1, queueS2) # start sending stuff from s1 to s2 
    s2.join() # wait till s2 daemon finishes
    # stage1.py
    import time
    import random

    class Stage1:

      def stage1(self, queueS1, queueS2):
        print("stage1")
        lala = []
        lis = [1, 2, 3, 4, 5]
        for i in range(len(lis)):
          # to avoid unnecessary waiting
          if not queueS2.empty():
            msg = queueS2.get()    # get msg from s2
            print("! ! ! stage1 RECEIVED from s2:", msg)
            lala = [6, 7, 8] # now that a msg was received, further msgs will be different
          time.sleep(1) # work
          random.shuffle(lis)
          queueS1.put(lis + lala)             
        queueS1.put('s1 is DONE')
    # stage2.py
    import time

    class Stage2:

      def stage2(self, queueS1, queueS2):
        print("stage2")
        while True:
            msg = queueS1.get()    # wait till there is a msg from s1
            print("- - - stage2 RECEIVED from s1:", msg)
            if msg == 's1 is DONE ':
                break # ends loop
            time.sleep(1) # work
            queueS2.put("update lists")             

[~ # ~ ~] Edit [~ # ~] : vient de trouver que vous pouvez utiliser Queue.get (False) = pour éviter le blocage lors de la réception de données. De cette façon, il n'est pas nécessaire de vérifier d'abord si la file d'attente est vide. Cela n'est pas possible si vous utilisez des tuyaux.

0
onofricamila