Python process tracklist, get cumulative timestamp of each track The code below parses a tracklist (sample input below) and generates a six-member tuple, including cumulative timestamps in mm:ss. (sample output at bottom).


couldn't easily see how to rewrite it from a for-loop to a generator get_track_with_cumulative_timestamp(itt)
I think we don't need a custom object, i.e. avoid this approach
generator will need to internally store state (tmm, tss) being the end-time of each song. So we yield each result with the start-time of each song; incrementing the time-arithmetic comes after that.
are there better idioms for the (mm,ss) modulo-60 counters? decimal.Decimal seems overkill. I suppose we could always pull a trick internally using one float to represent both (mm,ss)


Current not-so-great procedural code:

tracklist = """
1. Waiting For A Miracle 5:02
2. Bedroom Eyes 5:01
3. In Over My Head 4:31
4. Higher Ground / Written-By – S. Wonder* 3:38
5. Hot Blood 4:15
6. Running Away 4:28
7. I've Had Enough 3:47
8. Blacklisted / Guitar [Other] – Jonny Fean* 4:11
9. Last Thing At Night 2:49"""

tracklist = [t for t in tracklist.split('\n') if t]

import re

pat = re.compile(r'(?P&lt;no&gt;[0-9]+)\. (?P&lt;name&gt;.*) (?P&lt;mm&gt;[0-9]+):(?P&lt;ss&gt;[0-9]+)')

(tmm,tss) = (0,0)
result = []

for t in tracklist:
    m = pat.match(t)
    #print(m.groups())
    lmm, lss = int(m['mm']), int(m['ss'])

    result.append((int(m['no']), tmm, tss, lmm, lss, m['name']))
    #yield (int(m['no']), tmm, tss, lmm, lss, m['name']))

    tss += lss
    tmm += lmm
    if tss &gt;= 60:
        tmm += 1
        tss -= 60

# Output looks like this:
for _ in result: print('{} | {:02d}:{:02d} | {}:{:02d} | {}'.format(*_))


1 | 00:00 | 5:02 | Waiting For A Miracle
2 | 05:02 | 5:01 | Bedroom Eyes
3 | 10:03 | 4:31 | In Over My Head
4 | 14:34 | 3:38 | Higher Ground / Written-By – S. Wonder*
5 | 18:12 | 4:15 | Hot Blood
6 | 22:27 | 4:28 | Running Away
7 | 26:55 | 3:47 | I've Had Enough
8 | 30:42 | 4:11 | Blacklisted / Guitar [Other] – Jonny Fean*
9 | 34:53 | 2:49 | Last Thing At Night
Implicit tuples

(tmm,tss) = (0,0)


This shouldn't need any parens.

Generator


  couldn't easily see how to rewrite it from a for-loop to a generator 


It actually is quite easy. Make your code into a function, delete result, and replace result.append with yield.

Time spans


  are there better idioms for the (mm,ss) modulo-60 counters? 


Yes!

Custom objects


  I think we don't need a custom object


Named tuples take one line to declare, and suck less than unstructured data. So do that, at least.

Underscores

I just noticed that you're looping with an underscore as your loop variable. By convention this means "I'm not going to use this value"... but then you used it anyway. Give this variable a meaningful name.

Example

import re
from collections import namedtuple
from datetime import timedelta

TRACK_PAT = re.compile(r'(?P&lt;no&gt;[0-9]+)\. (?P&lt;name&gt;.*) (?P&lt;mm&gt;[0-9]+):(?P&lt;ss&gt;[0-9]+)$', re.M)
Track = namedtuple('Track', ('number', 'time', 'length', 'name'))


def parse_track(body):
    t_total = timedelta()
    for match in TRACK_PAT.finditer(body):
        length = timedelta(minutes=int(match['mm']), seconds=int(match['ss']))
        yield Track(int(match['no']), t_total, length, match['name'])
        t_total += length


for track in parse_track(
"""
1. Waiting For A Miracle 5:02
2. Bedroom Eyes 5:01
3. In Over My Head 4:31
4. Higher Ground / Written-By – S. Wonder* 3:38
5. Hot Blood 4:15
6. Running Away 4:28
7. I've Had Enough 3:47
8. Blacklisted / Guitar [Other] – Jonny Fean* 4:11
9. Last Thing At Night 2:49"""
):
    print(f'{track.number} | {track.time} | {track.length} | {track.name}')