为什么Python酸洗库会抱怨那些不存在的类成员呢?

时间:2016-10-12 20:42:43

标签: python serialization pickle

我有以下简单的类定义:

def apmSimUp(i):
    return APMSim(i)

def simDown(sim):
    sim.close()

class APMSimFixture(TestCase):

    def setUp(self):
        self.pool = multiprocessing.Pool()
        self.sims = self.pool.map(
            apmSimUp,
            range(numCores)
        )

    def tearDown(self):
        self.pool.map(
            simDown,
            self.sims
        )

其中类APMSim纯粹由简单的python原始类型(字符串,列表等)定义,唯一的例外是静态成员,它是一个多处理管理器.list

但是,当我尝试执行此类时,我收到以下错误信息:

Error
Traceback (most recent call last):
  File "/home/peng/git/datapassport/spookystuff/mav/pyspookystuff_test/mav/__init__.py", line 77, in setUp
    range(numCores)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 251, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 567, in get
    raise self._value
MaybeEncodingError: Error sending result: '[<pyspookystuff.mav.sim.APMSim object at 0x7f643c4ca8d0>]'. Reason: 'TypeError("can't pickle thread.lock objects",)'

这很奇怪,因为无法在任何地方找到thread.lock,我严格避免使用任何多线程组件(如您所见,只使用了多处理组件)。这些组件中没有一个存在于我的类中,或者只作为静态成员存在,我该怎么做才能使这个类可选?

顺便说一句,有没有办法将黑羊成员排除在酸洗之外?像Java的@transient注释?

非常感谢您的帮助!

更新:以下是我的完整APMSim课程,请查看是否有任何违反选择性的内容:

usedINums = mav.manager.list()
class APMSim(object):
    global usedINums

    @staticmethod
    def nextINum():
        port = mav.nextUnused(usedINums, range(0, 254))
        return port

    def __init__(self, iNum):
        # type: (int) -> None

        self.iNum = iNum
        self.args = sitl_args + ['-I' + str(iNum)]

    @staticmethod
    def create():
        index = APMSim.nextINum()
        try:
            result = APMSim(index)
            return result
        except Exception as ee:
            usedINums.remove(index)
            raise

    @lazy
    def _sitl(self):
        sitl = SITL()
        sitl.download('copter', '3.3')
        sitl.launch(self.args, await_ready=True, restart=True)
        print("launching .... ", sitl.p.pid)
        return sitl

    @lazy
    def sitl(self):
        self.setParamAndRelaunch('SYSID_THISMAV', self.iNum + 1)
        return self._sitl

    def _getConnStr(self):
        return tcp_master(self.iNum)

    @lazy
    def connStr(self):
        self.sitl
        return self._getConnStr()

    def setParamAndRelaunch(self, key, value):

        wd = self._sitl.wd
        print("relaunching .... ", self._sitl.p.pid)
        v = connect(self._getConnStr(), wait_ready=True) # if use connStr will trigger cyclic invocation
        v.parameters.set(key, value, wait_ready=True)
        v.close()
        self._sitl.stop()
        self._sitl.launch(self.args, await_ready=True, restart=True, wd=wd, use_saved_data=True)
        v = connect(self._getConnStr(), wait_ready=True)
        # This fn actually rate limits itself to every 2s.
        # Just retry with persistence to get our first param stream.
        v._master.param_fetch_all()
        v.wait_ready()
        actualValue = v._params_map[key]
        assert actualValue == value
        v.close()

    def close(self):

        self._sitl.stop()
        usedINums.remove(self.iNum)

lazy decorator来自这个库:

https://docs.python.org/2/tutorial/classes.html#generator-expressions

1 个答案:

答案 0 :(得分:0)

查看类的外观会很有帮助,但如果它有来自multiprocessing的方法,则默认情况下可能会遇到问题。多处理对象也可以使用锁,这些(显然)是不可用的。

您可以使用__getstate__方法或__reduce__(记录在同一位置)自定义酸洗。