Establishing why an object can't be pickled

前端 未结 4 2055
小蘑菇
小蘑菇 2021-01-11 14:37

I\'m receiving an object, t, from an api of type Object. I am unable to pickle it, getting the error:

  File \"p.py\", line 55, in          


        
4条回答
  •  情歌与酒
    2021-01-11 14:45

    Here's an extension of Alastair's solution, in Python 3.

    It:

    • is recursive, to deal with complex objects where the problem might be many layers deep.

      The output is in the form .x[i].y.z.... to allow you to see which members were called to get to the problem. With dict it just prints [key/val type=...] instead, since either keys or values can be the problem, making it harder (but not impossible) to reference a specific key or value in the dict.

    • accounts for more types, specifically list, tuple and dict, which need to be handled separately, since they don't have __dict__ attributes.

    • returns all problems, rather than just the first one.

    def get_unpicklable(instance, exception=None, string='', first_only=True):
        """
        Recursively go through all attributes of instance and return a list of whatever
        can't be pickled.
    
        Set first_only to only print the first problematic element in a list, tuple or
        dict (otherwise there could be lots of duplication).
        """
        problems = []
        if isinstance(instance, tuple) or isinstance(instance, list):
            for k, v in enumerate(instance):
                try:
                    pickle.dumps(v)
                except BaseException as e:
                    problems.extend(get_unpicklable(v, e, string + f'[{k}]'))
                    if first_only:
                        break
        elif isinstance(instance, dict):
            for k in instance:
                try:
                    pickle.dumps(k)
                except BaseException as e:
                    problems.extend(get_unpicklable(
                        k, e, string + f'[key type={type(k).__name__}]'
                    ))
                    if first_only:
                        break
            for v in instance.values():
                try:
                    pickle.dumps(v)
                except BaseException as e:
                    problems.extend(get_unpicklable(
                        v, e, string + f'[val type={type(v).__name__}]'
                    ))
                    if first_only:
                        break
        else:
            for k, v in instance.__dict__.items():
                try:
                    pickle.dumps(v)
                except BaseException as e:
                    problems.extend(get_unpicklable(v, e, string + '.' + k))
    
        # if we get here, it means pickling instance caused an exception (string is not
        # empty), yet no member was a problem (problems is empty), thus instance itself
        # is the problem.
        if string != '' and not problems:
            problems.append(
                string + f" (Type '{type(instance).__name__}' caused: {exception})"
            )
    
        return problems
    

提交回复
热议问题