JSON として反復可能な Python クラスをエンコードしたいのですが、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)
ヘルパーは主に flatten-Method と、リスト内のすべての要素が特定のタイプであるかどうかを確認できるメソッドを実装します。
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_iterator オブジェクトです。なぜですか? これを修正するにはどうすればよいですか? (InnerTable から反復可能な関数を削除することは、時間的な理由と、これら 2 つの関数を一緒にすべきではない理由が見当たらないため、私にとって非常に不快であることに注意してください。)