TypeError: can't pickle file objects webpy and subprocess

TypeError: can't pickle file objects webpy and subprocess

我正在尝试使以下代码成为可能。但我不断收到 "TypeError: can't pickle file objects" 错误。我是 python 和 webpy 的新手。谁能告诉我如何实现此代码。

import web 
import subprocess

web.config.debug = False
urls = ( 
   "/start", "start",
   "/end", "end"
)
app = web.application(urls, locals())
s = web.session.Session(app, web.session.DiskStore('sessions'), initializer={"p": None})

class start:
    def GET(self):
        s.p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return ""

class end:
    def GET(self):
        out, err = s.p.communicate();
        return out 

if __name__ == "__main__":
    app.run()

我一直看到的错误是 python27/lib/python2.7/copy_reg.py”,第 70 行,_reduce_ex 引发 TypeError,"can't pickle %s objects" % base.name 类型错误:无法腌制文件对象

我自己是一个网络新手。然而,在做了一些 "research" 之后,似乎 webpy 不能 pickle subprocess.Popen 对象 [1]。 因此,让我们尝试以下方法——即在 end 响应中创建它并打印其输出。

换句话说:

import web 
import subprocess

web.config.debug = False
urls = ( 
   "/start", "start",
   "/end", "end"
)
app = web.application(urls, locals())
s = web.session.Session(
        app, web.session.DiskStore('sessions'), initializer={"p": None})

class start:
    def GET(self):
        s.p = ['ls', '-a']
        return ""

class end:
    def GET(self):
        out, err = subprocess.Popen(
                       s.p , stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE).communicate()
        s.kill() # kill the session.
        return out 

if __name__ == "__main__":
    app.run()

[1] 如您所见:

import pickle
import subprocess

with open('bla', 'wb') as f:
    pickle.dump(subprocess.Popen(['ls'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE), f)

subprocess.Popen returns 一个文件描述符,从回溯中我推断 pickle 无法序列化文件描述符。

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/lib64/python2.7/pickle.py", line 1370, in dump
    Pickler(file, protocol).dump(obj)
  File "/usr/lib64/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/usr/lib64/python2.7/pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "/usr/lib64/python2.7/pickle.py", line 419, in save_reduce
    save(state)
  File "/usr/lib64/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib64/python2.7/pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "/usr/lib64/python2.7/pickle.py", line 663, in _batch_setitems
    save(v)
  File "/usr/lib64/python2.7/pickle.py", line 306, in save
    rv = reduce(self.proto)
  File "/usr/lib64/python2.7/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle file objects

除此之外,Pickle documentation 提到它仅支持 布尔值、整数、浮点数、复数、字符串、字节对象、字节数组,和 None。因此,似乎没有希望。

编辑

如果您坚持创建进程的文件描述符,当收到来自客户端的 start 请求时,您可以使用字典将会话映射到文件描述符。

应该是这样的:

s = web.session.Session(
        app, web.session.DiskStore('sessions'), initializer={"p": None})
session_map = {}

class start:
    def GET(self):
        session_map[s] = subprocess.Popen(['ls', '-a'],
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.PIPE)
        return ""

class end:
    def GET(self):
        out, err = session_process[s].communicate()
        session_process.pop(s, None)
        s.kill
        return out