import numpy as np from collections.abc import Iterable # the following now is a singleton metaclass class MetaSingletonHash(type): """ Singleton metaclass based on hash First creates object to be able to test hash. If same hash is found, return old object and discard new one, otherwise return old one. Usage: class X(Y, metaclass = MetaSingletonHash) class X needs to provide a __hash__ function """ def __call__(*args, **kwargs): cls = args[0] try: cache = cls._cache except: cache = dict() cls._cache = cache obj = type.__call__(*args, **kwargs) key = (cls.__name__, obj.__hash__()) return cache.setdefault(key, obj) class Slice(object): """ Slice iterator object. """ def __init__(self, *args, **kwargs): """ Construct from slice indices or slice object. Provide optional object size. """ if len(args) == 1 and isinstance(args[0], slice): self.slice = args[0] else: self.slice = slice(*args) self.size = kwargs.pop('size', None) assert len(kwargs) == 0 def __iter__(self): """ Slice object iterator. """ if self.size is None: self.size = max(self.slice.start, self.slice.stop) + 1 xslice = self.slice.indices(self.size) for i in range(*xslice): yield i def iter(self, size = None): """ Return iterator with defined object size. """ size = self.size for i in self.__iter__(): yield i self.size = size def iterable(x): """ convert things to an iterable, but omit strings May need to add other types. """ if isinstance(x, str): x = (x,) if isinstance(x, np.ndarray) and len(x.shape) == 0: x = (x,) if not isinstance(x, (Iterable, np.ndarray)): x = (x,) return x def is_iterable(x): """ return whether is a true iterable incluidng numpy.ndarra, but not string """ if isinstance(x, np.ndarray) and len(x.shape) == 0: return False return isinstance(x, (Iterable, np.ndarray)) and not isinstance(x, str)