Let’s start from the beginning. According to documentation:
Functions are first-class Objects.
That is, in Python the functions are "first-class citizens": they are treated as if they were "normal" values, can be placed in lists, assigned to a variable, passed as parameter to other functions, etc. On this subject, you can read more here, here and here.
Therefore, a function can be assigned to a variable:
def square(y):
        return y ** 2
    
def cube(y):
        return y ** 3
# atribui a função a uma variável
funcao = square
# como "funcao" aponta para "square", posso chamá-la normalmente
print(funcao(3)) # 9
# atribui outra função na mesma variável
funcao = cube
# agora "funcao" aponta para "cube"
print(funcao(3)) # 27
And I can also create a list of various functions, scroll through that list in one loop and call them all:
def square(y):
        return y ** 2
    
def cube(y):
        return y ** 3
# lista contendo as funções
funcs = [square, cube]
# para cada função da lista, chamá-la passando o número 3 como argumento
for funcao in funcs:
    print(f'chamando {funcao.__name__}: {funcao(3)}')
The output of this code is:
chamando square: 9
chamando cube: 27
Now about the map: all he does is apply a function to all the elements of an eternal. That is, if I do:
def dobro(n):
    return n * 2
valores = [1, 2, 3]
for result in map(dobro, valores):
    print(result)
This will print 2, 4 and 6, for map(dobro, valores) apply the function dobro to each of the elements on the list valores. Essentially, this would be equivalent to:
for valor in valores:
    print(dobro(valor))
But in your case the list has no values that are passed to a function. What it has are functions that will be called with a certain value. I mean, it would be like doing this:
# para cada função da lista "funcs", chamá-la passando o "3" como argumento
for funcao in funcs:
    print(funcao(3))
And in this case, the equivalent using map would have to be:
for result in map(lambda funcao: funcao(3), funcs):
    print(result)
That is, the function that map receives is a lambda (that in the background is also a function), which takes as argument a function and the flame (passing, in this case, the number 3 as argument). That is, instead of myself calling the function directly within the loop, is the map that the flame and returns the result (so within the for I can already catch the direct result).
But in your case you’re not iterating for map, and yes taking his result and passing to list, which in turn creates a list containing all the results. That is, when you do:
valor = map(lambda funcao: funcao(3), funcs)
print(list(valor)) # [9, 27]
Would be equivalent to doing:
results = [] # cria uma lista vazia
# para cada resultado do map, adicioná-lo na lista
for result in map(lambda funcao: funcao(3), funcs):
    results.append(result)
print(results) # [9, 27]
And finally, in your code all this is done inside a loop, iterating by list values [0, 1, 2, 3, 4]. In the above examples I always passed the number 3 for the duties, but in its loop he does it for all values on the list.
That is, first he calls the functions to the 0 and print the list with the results, then do the same for the 1, to the 2 etc..
And just for the record, another way to create this list of results would be to use a comprehensilist on:
for i in lista:
    print([ funcao(i) for funcao in funcs ])