JSONPickle将自己的迭代器类作为列表迭代器而不是其

2024-10-01 09:30:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我想将iterable的Python类编码为JSON,但是JSON Pickle在解码时将其作为列表生成器返回。这是我的代码:

from typing import Iterable
from Helper import Helper
from RCEnum import RCEnum
import jsonpickle


class InnerTable:

def __init__(self, rows, cols):
    if not Helper.lio(int, rows, cols) or rows<1 or cols<1: raise Exception("Invaild rows and or cols")
    ret={"rows":[[None]*(cols+1)], "cols":[[None]*(rows+1)]}
    tid=[]
    self.rows=rows
    self.cols=cols
    for r in range(1, rows+1):
        ret["rows"].append([None])
        for c in range(1, cols+1):
            f=str(r)+"&"+str(c)
            tid.append((r, c))
            ret["rows"][-1].append(f)
            if c==len(ret["cols"]):
                ret["cols"].append([None, f])
            else:
                ret["cols"][c].append(f)
    self.table=ret
    self.tid=tid
    self.element=0

def __iter__(self):
    return self

def __next__(self):
    try:
        i=self.element
        self.element+=1
        return self[self.tid[i]]
    except IndexError:
         self.element=0
         raise StopIteration

def __len__(self):
    return self.cols*self.rows


def __getitem__(self, item):
    if item=="rows":
        return self.table["rows"]
    elif item=="cols":
        return self.table["cols"]
    elif isinstance(item, Iterable) and len(item)==2:
        if isinstance(item[0], bool) and isinstance(item[1], int):
            if item[0]:
                return self[self.tid[item[1]]]
            else:
                return self[self.tid[-item[1]]]
        if Helper.lio(int, item):
            return self[item[0]][item[1]]
    else:
        return self.table["rows"][item]

def changeElement(self, a, b, nv, loc="rows"):
    try:
        if not (loc.lower()==RCEnum.C.value or loc.lower()==RCEnum.R.value): raise IndexError("not a valid location ")
        loc2=RCEnum.C.value if loc.lower()==RCEnum.R.value else RCEnum.R.value
        self[loc][a][b]=nv
        self[loc2][b][a]=nv
    except Exception as e:
        print("Not changed. Reason "+str(e))

def getNFieldsInRoCAC(self, roc, l, direct=1, loc="rows"):
    if not (loc.lower()==RCEnum.C.value or loc.lower()==RCEnum.R.value): raise IndexError("not a valid location ")
    fields=self[loc][roc] if direct>0 else [None]+list(reversed(self[loc][roc]))[:-1]
    ret=[]
    alwaysNotIn=[]
    for ni in range(1, len(self[loc])):
        if ni==roc: continue
        alwaysNotIn.extend(self[loc][ni][1:])
    for i in range(1, len(fields)+1):
        if i+l>len(fields): break
        current=fields[i:i+l]
        currentNonFields=fields[1:i]+fields[i+l:]+alwaysNotIn
        ret.append([current, currentNonFields])
    return ret


def __repr__(self):
    return "InnerTable "+str(self.rows)+"*"+str(self.cols)

def __str__(self):
    rs=""
    for ri in self["rows"][1:]:
        rs+=str(ri[1:])+"\n "
    return rs

def toJSON(self):
    return  jsonpickle.encode(self)

helper主要实现flatten方法和一个让我检查列表中的每个元素是否属于某个类型的方法:

from typing import Iterable

class Helper:

    @staticmethod
    def flatten(items, useValues=True):
        """Yield items from any nested iterable; see Reference."""
        for x in items:
            if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
                for sub_x in Helper.flatten(x.values() if isinstance(x, dict) and useValues else x):
                    yield sub_x
            else:
                yield x

    @staticmethod
    def lio(cl, *inst):
        inst=list(Helper.flatten(inst))
        return all(map(lambda i:isinstance(i, cl), inst))

RCEnum是惊喜,惊喜一个简单的枚举:

from enum import Enum

class RCEnum(Enum):
    R="rows"
    r="row"
    C="cols"
    c="col"

但现在到了重要的部分:

it=InnerTable(1, 4)
it2=jsonpickle.decode(it.toJSON())

出于某种原因,it2不是InnerTable,而是list\u迭代器对象,为什么?我能做些什么来纠正这个问题(请注意,从InnerTable中删除iterable函数对我来说是非常不愉快的,这既有时间方面的原因,也有我看不出这两个函数不能同时使用的原因。)


Tags: inselfhelperforreturnifdefitem