当前位置:  开发笔记 > 编程语言 > 正文

如何在python中跨脚本共享变量?

如何解决《如何在python中跨脚本共享变量?》经验,为你挑选了5个好方法。

以下不起作用

one.py

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

two.py

import shared
print shared.value

在两个命令行上运行:

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

(第二个得到属性错误,这是正确的).

有没有办法实现这一点,即在两个脚本之间共享一个变量?



1> sdaau..:

希望在这里记下关于这个问题的笔记是可以的.

首先,我很欣赏OP中的示例,因为这也是我开始的地方 - 尽管它让我想到了shared一些内置的Python模块,直到我在模块之间的[Tutor] Global Variables中找到了一个完整的例子?? .

但是,当我寻找"在脚本之间共享变量"(或进程)时 - 除了Python脚本需要使用在其他Python源文件中定义的变量(但不一定是运行进程)的情况 - 我经常偶然发现其他两个用例:

脚本将自身分成多个子进程,然后在同一台PC上并行运行(可能在多个处理器上)

脚本会生成多个其他子进程,然后在同一台PC上并行运行(可能在多个处理器上)

因此,大多数关于"共享变量"和"进程间通信"(IPC)的命中讨论了这两个案例; 然而,在这两种情况下,人们都可以观察到"父母","孩子"通常会有一个参考.

然而,我感兴趣的是运行多个相同脚本的调用,独立运行,以及在单例/单个实例中在Python之间共享数据(如在Python中如何共享对象实例的多个调用)模式.上述两种情况并未真正解决这类问题 - 相反,它本质上简化为OP中的示例(跨两个脚本共享变量).

现在,在Perl中处理这个问题时,有IPC :: Shareable ; "允许您将变量绑定到共享内存",使用"整数或4个字符串[1],作为跨进程空间的数据的公共标识符".因此,没有临时文件,也没有网络设置 - 我认为这对我的用例很有用; 所以我在Python中寻找相同的东西.

然而,正如@Drewfer所接受的回答所指出的那样:" 如果不将信息存储在解释器的两个实例之外的某个地方,你将无法做你想做的事情 "; 换句话说:要么必须使用网络/套接字设置 - 要么必须使用临时文件(ergo,没有共享RAM用于" 完全独立的python会话 ").

现在,即使考虑到这些因素,也很难找到工作示例(除了pickle) - 在mmap和多处理的文档中也是如此.我设法找到了一些其他的例子 - 这些例子也描述了文档没有提到的一些陷阱:

用法mmap:使用mmap |在两个不同的脚本中共享Python数据的工作代码 schmichael的博客

演示两个脚本如何更改共享值

请注意,此处创建临时文件作为已保存数据的存储 - mmap只是用于访问此临时文件的特殊接口

用法multiprocessing:工作代码:

多处理下的Python多处理RemoteManager.Process - SyncManager(via manager.start())with shared的工作示例Queue; 服务器写入,客户端读取(共享数据)

多处理模块和pyro的比较?- 使用共享自定义类的BaseManager(via server.serve_forever())工作示例; 服务器写入,客户端读取和写入

如何将python dict与多处理同步 - 这个答案对multiprocessing陷阱有很好的解释,并且是SyncManager(通过manager.start())共享字典的一个工作示例; 服务器什么都不做,客户端读写

感谢这些例子,我想出了一个例子,它与示例基本相同mmap,使用" 同步python dict "示例的方法 - 使用BaseManager(manager.start()通过文件路径地址)和共享列表; 服务器和客户端读写(粘贴在下面).注意:

multiprocessing经理可以通过manager.start()或启动server.serve_forever()

serve_forever()锁 - start()没有

有自动记录功能multiprocessing:它似乎可以正常使用start()ed进程 - 但似乎忽略了那些serve_forever()

地址规范multiprocessing可以是IP(套接字)或临时文件(可能是管道?)路径; 在multiprocessing文档中:

大多数示例使用multiprocessing.Manager()- 这只是一个返回a 的函数(不是类实例化)SyncManager,它是一个特殊的子类BaseManager; 和使用start()- 但不是独立运行的脚本之间的IPC; 这里使用了文件路径

serve_forever()在独立运行的脚本之间,很少有其他示例用于IPC; 这里使用IP /套接字地址

如果未指定地址,则会自动使用临时文件路径(请参阅16.6.2.12.记录有关如何查看此内容的示例)

除了" 同步python dict "帖子中的所有陷阱之外,如果列表中还有其他的陷阱.该帖子指出:

dict的所有操作必须用方法完成而不是dict赋值(syncdict ["blast"] = 2会因为多处理共享自定义对象的方式而失败)

dict['key']获取和设置的解决方法是使用dict公共方法getupdate.问题是没有这样的公共方法可供选择list[index]; 因此,对于共享的名单中,除了我们要注册__getitem____setitem__方法(这是私人的list)的exposed,这意味着我们还必须重新注册所有的公共方法list,以及:/

嗯,我认为这些是最关键的事情; 这些是两个脚本 - 它们可以在不同的终端中运行(服务器优先); 使用Python 2.7在Linux上开发的注释:

a.py (服务器):

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 
    # 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 (客户)

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

最后一点,在Linux /tmp/mypipe上创建 - 但是是0字节,并且具有属性srwxr-xr-x(对于套接字); 我想这让我感到高兴,因为我既不必担心网络端口,也不担心临时文件:)

其他相关问题:

Python:可以在两个独立的进程之间共享内存数据(非常好的解释)

高效的Python到Python IPC

Python:将变量发送到另一个脚本



2> Drewfer..:

如果不将信息存储在解释器的两个实例外部的某个位置,您将无法执行所需的操作.
如果它只是你想要的简单变量,你可以轻松地将python dict转储到带有pickle模块的文件中,然后在脚本2中重新加载它.例:

one.py

import pickle

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

two.py

import pickle

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



3> 小智..:

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

two.py

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



4> Gabriel Reid..:

你在这里尝试做什么(通过单独的python解释器在Python模块中存储共享状态)将不起作用.

模块中的值可以由一个模块更新,然后由另一个模块读取,但这必须在同一个Python解释器中.你在这里做的实际上是一种进程间通信; 这可以通过两个进程之间的套接字通信来完成,但它远远不如你期望在这里工作那么简单.



5> AmitE..:

您可以使用相对简单的mmap文件。您可以使用shared.py存储公共常量。以下代码将在不同的python解释器\脚本\ processes中工作

shared.py:

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

*“全局”是Windows全局名称的语法

一个.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)                                                                      

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

*此代码是为Windows编写的,Linux可能需要一些调整

更多信息-https: //docs.python.org/2/library/mmap.html

推荐阅读
落单鸟人
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有