もう少し辞書型にこだわる

辞書型にこだわったが、もう少し考えた。
辞書型とリスト型も対応し、考え方はシンプルになる。
class Container():

	data = None

	def _dot2bra(self, path):
		if '"' in path: return path
		path = '["' + ( path.replace('].',']["').replace('.','"]["').replace('[','"][') + '"]' ).replace(']"]',']')
		return path.replace('[""]','')

	def _parse(self, path):
		if path == '': return ''
		path = self._dot2bra(path)
		keys = path[1:-1].split('][')
		for i,key in enumerate(keys): keys[i] = key.strip('"') if key[0]=='"' and key[-1]=='"' else int(key)
		return keys

	def _make_path(self, keys):
		path = ''
		for key in keys: path += ('[{}]' if type(key) is int else '["{}"]').format(key)
		return path

	def get_paths(self):
		def _get_paths(data):
			paths = []
			if type(data) is dict:
				for k, v in data.items():
					paths.append('["{}"]'.format(k))
					for path in _get_paths(v): paths.append('["{}"]{}'.format(k,path))
			elif type(data) is list:
				for k, v in enumerate(data):
					paths.append('[{}]'.format(k))
					for path in _get_paths(v): paths.append('[{}]{}'.format(k,path))
			return paths
		return _get_paths(self.data)

	def exists_path(self, path):
		try:
			keys = self._parse(path)
			data = self.data
			for key in keys: data = data[key]
			return True
		except: return False

	def get(self, path=''):
		if path == '': return self.data
		try:
			#path = self._dot2bra(path)
			#return eval('self.data{}'.format(path))
			keys = self._parse(path)
			data = self.data
			for key in keys: data = data[key]
			return data
		except: return None

	def set(self, value, path=''):
		if path == '':
			self.data = value
			return True
		try:
			path = self._dot2bra(path)
			exec('self.data{} = value'.format(path))
			return True
		except: return False

	def add(self, value, path=''):
		try: keys = self._parse(path)
		except: return False
		for i in range(len(keys)-1):
			path = self._make_path(keys[:i+1])
			try: data = eval('self.data{}'.format(path))
			except: pass
		try:
			if type(keys[-1]) is int: eval('self.data{}.append(value)'.format(path))
			else: eval('self.data{}.update({{"{}":value}})'.format(path, keys[-1]))
			return True
		except: return False

	def pop(self, path):
		keys = self._parse(path)
		key = keys.pop()
		path = self._make_path(keys)
		try:
			data = eval('self.data{}'.format(path))
			if type(data) is dict:
				value = data[key]
				del data[key]
				return value
			elif type(data) is list: return data.pop(key)
		except: return None
2020/07/29 05:45
タグ