Я имею в виду функциональность, которая позволяет вставлять заголовок заголовка перед записью, где изменяется какое-либо поле, или нижний колонтитул с итогами после изменения. Как в MS Access в свое время.
В настоящее время используется итерируемый объект и лямбда-выражения для проверки разрывов следующим образом:
Код: Выделить всё
from typing import Literal, Callable
class BreakResult():
def __init__(self, name, state, slice_start, data=[]):
self.name = name
self.state = state
self.slice_start = slice_start
def __bool__(self):
# Return True if the list is non-empty
return self.state
# Define behavior when used in an integer context
def __int__(self):
return self.slice_start
def __str__(self):
return self.name if self.state else ""
class BreakForIterable():
def __init__(self, name, break_lambda:Callable, where:Literal['after', 'before']='after'):
self.name = name
self.break_lambda = break_lambda
self.where = where
self._slice_start = 0
self._state = False
@property
def slice_start(self):
pass
def __call__(self, i, data):
# returns true, slice_start or None, slice_end or none
if self.where == "before":
# return true if:
# - record number is 0
# - lambda returns different values for current record and the previous one
# and set the slice start to the current record
if i == 0:
slice_start = self._slice_start
self._slice_start = i
return BreakResult(self.name, True, slice_start)
elif self.break_lambda(data[i]) != self.break_lambda(data[i-1]):
slice_start = self._slice_start
self._slice_start = i
return BreakResult(self.name, True, slice_start)
else:
return BreakResult(self.name, False, None)
elif self.where == "after":
# return true if:
# - record number is equal to the last
# - lambda returns different values for current record and the next one
# and set the slice start to the current record
if i == 0:
return BreakResult(self.name, False, None)
elif i == len(data) - 1:
slice_start = self._slice_start
self._slice_start = i + 1
return BreakResult(self.name, True, slice_start)
elif self.break_lambda(data[i]) != self.break_lambda(data[i+1]):
slice_start = self._slice_start
self._slice_start = i + 1
return BreakResult(self.name, True, slice_start)
else:
return BreakResult(self.name, False, None)
return BreakResult(self.name, False, None)
class IterableWithBreaks():
def __init__(self, data):
self.data = data # this is the data list
self.breaks = [] # this is the list of breaks. Order is important
def add_break(self, name, break_lambda, where="after"):
self.breaks.append(BreakForIterable(name, break_lambda, where))
return self
def check_breaks(self, i, where:Literal['after', 'before']):
rl = []
for b in [ b for b in self.breaks if b.where == where]:
r = b(i, self.data)
rl.append(r)
return [ r for r in rl if r ]
def __iter__(self):
self._index = 0 # Initialize the index for iteration
return self
def __next__(self):
if self._index < len(self.data):
result = self.data[self._index]
self._index += 1
return result
else:
raise StopIteration # End of the iteration
def __getitem__(self, index):
return self.data[index]
# Define behavior for setting elements
def __setitem__(self, index, value):
self.data[index] = value
# Define behavior for deleting elements
def __delitem__(self, index):
del self.data[index]
Есть ли лучший подход? Или есть библиотеки, которые делают это лучше? Подойдет все, от инструментов отчетности (с открытым исходным кодом) до библиотек Python (лучше, поскольку я смогу лучше управлять графикой).
Подробнее здесь: https://stackoverflow.com/questions/790 ... nd-headers