from collections import namedtuple, OrderedDict from lib import * def virtual_container(virtual_container, objects_type): """Used to create a virtual object given a the type of container and what it holds. The object_type needs to only have normal values.""" for name in objects_type: if name.startswith("__") and name.endswith("__"): raise ValueError("Arguments should be not start and end with __") if issubclass(virtual_container,list): def handle_binding(objects_type): class my_virtual_container_class: """This singleton class represents the container""" def __init__(self): """The attributes for the virtual container""" #Define the default values __vals__=OrderedDict([(key,None) for key in objects_type]) #Then function to access them. Note the default parameter for the lambda to #enforce early binding d={} for key in objects_type: def func_factory(key): """Function causes early binding for key""" def make_attribute(self, items=None): """Called on the attr_cl. This function will return the list for the attribute. As a default, this is [], but a list can also be passed in""" if items==None: items=[] if self.__vals__[key]==None: self.__vals__[key]=items else: raise RuntimeError("This attribute has been already initialised") return self.__vals__[key] return make_attribute #Add the function to this class d[key]=func_factory(key) d["__vals__"]=__vals__ #Construct a named tuple from this self.__attr__=type('attr_cl',(), d)() #Define the operators def __iter__(self): vals=self.__attr__.__vals__ return zip(*vals.values()) def __contains__(self, x): return x in self.__iter__() def __delitem__(self, i): #Handles items and slices vals=self.__attr__.__vals__ for seq in vals.values(): del seq[i] def __getitem__(self, i): #Handles items and slices vals=self.__attr__.__vals__ #Make it a slice isslice=isinstance(i, slice) if not isslice: i=slice(i, i+1) ret=[seq[i] for seq in vals.values()] ret=list(zip(*ret)) if not isslice: ret=ret[0] return ret def __setitem__(self, i, x): #Handles items and slices vals=self.__attr__.__vals__ #Split slices if isinstance(i,slice): x=zip(*x) for seq, setTo in zip(vals.values(), x): seq[i]=setTo def __add__(self, myList): return list(self.__iter__())+myList def __iadd__(self, myList): vals=self.__attr__.__vals__ for seq, extra in zip(vals.values(), zip(*myList)): seq+=extra return self def __str__(self): s="Proxy: Names: "+" ".join(self.__attr__.__vals__.keys()) s+=" Vals: "+" ".join(map(str,self.__iter__())) return s return my_virtual_container_class() return handle_binding(objects_type) #Example code coordinates_2d=["x","y"] coordinates=virtual_container(list, coordinates_2d) x=coordinates.__attr__.x([1,2,3,4]) y=coordinates.__attr__.y([2,3,4,5]) print(coordinates[3]) print(coordinates[3:4]) print(coordinates[2:4]) for m in coordinates: print(m, end=" ") print() print(coordinates+[1,2]) coordinates[1]=(0,0) print(x,y) coordinates+=[(9,9)] print("##",coordinates[:]) del coordinates[1:3] print(coordinates[:]) coordinates[0:2]=[(0,1),(3,4)] print(coordinates) #Testing second group of coordinates coordinates2=virtual_container(list, coordinates_2d) x2=coordinates2.__attr__.x([]) y2=coordinates2.__attr__.y([]) print("List is: ", end=" ") for z in coordinates2: print(z,end=" ") print() print(bool(coordinates2)) print(coordinates[0])