Как на Python обеспечить вывод корней уравнения списком (вопрос о генераторах и модуле timeit)?

Реализую функцию нахождения корней методом дихотомии. Не стану здесь объяснять его суть - код реализован, причем достаточно корректно. Однако вот в чем загвоздка.

Функция dichotomy() содержит логику расчета корней уравнения, и мне надо получить их вывод в удобочитаемом виде. Сейчас когда ставлю print(root), я получаю вывод в столбик. Мне же требуется списком в строку, причем с нужным количеством цифр после запятой.

По отдельности это реализовано:

import numpy as np
import timeit

start_time = time.time()
res = list(dichotomy(0.0001,184,10000, 0.000001)) # написанная нами функция с заданными пользователем аргументами
print('Корни по методу дихотомии находятся в точках:')
print(', '.join(map(lambda x: f'{x:.4f}', res)))
print(f'Время счета по модулю timeit: ', timeit.timeit('dichotomy(0.0001,184,10000, 0.000001)', 'from __main__ import dichotomy'), 'seconds')

Однако занести код вывода в тело функции не получается. Это первая трудность.

Вторая: если объявляю время счета timeit.timeit() вне функции, то метод работает, внутри - уже нет. В общем сейчас этот код дает сбои в финальных строках:

import numpy as np
import timeit

def f(x):
    return 1.2-np.log(x)-4*np.cos(2*x)

def dichotomy (a,b,n, eps): # отрезок от a до b делим на n частей, погрешность eps
    """
    Функция отделения и уточнения корня
    """
    assert a!=0,  'a равно 0'
    assert b!=0, 'b равно 0'
    
    # сначала отделим корни
    grid=np.linspace(a, b, n)
    
    # далее уточним корни
    for x,y in zip(grid, grid[1:]):
        if f(x) * f(y) > 0: 
            continue
        root = None
        while ( abs(f(y)-f(x)) )>eps:    
            mid = (y+x)/2                   
            if f(mid) == 0 or f(mid)<eps:   
                root = mid                 
                break
            elif (f(mid) * f(x)) < 0:       
                y = mid                     
            else:
                x = mid                     
        if root:
            yield root
         #   print(root) # дает вывод столбиком - неудобно, потому пробуем ниже:
            res = list(root)   # ОШИБКА здесь!
            print(', '.join(map(lambda x: f'{x:.4f}', res)))

    print(f'Время счета по модулю timeit: ', timeit.timeit('dichotomy(0.0001,184,10000, 0.000001)', 'from __main__ import dichotomy'), 'seconds')

print(list(dichotomy(0.0001,184,10000, 0.000001))) # здесь юзер пытается подставить в функцию значения своих аргументов и получить распечатку корней

На выходе сейчас ошибка с указанием на res = list(root):

TypeError: 'numpy.float64' object is not iterable


Ответы (1 шт):

Автор решения: CrazyElf

Ну тут возможны разные варианты. Но если вы делаете именно генератор, то лучше выводить результат уже после работы генератора:

# получаем результат
res = list(dichotomy(0.0001,184,10000, 0.000001))

# выводим результат
print(', '.join(map(lambda x: f'{x:.4f}', res)))

А из генератора две строки после yield root просто уберите.

Если же вы хотите делать печать именно в генераторе, то будет не совсем красиво - придётся следить за запятыми, либо в конце будет лишняя запятая. Примерно можно сделать как-то так в конце функции:

        if root:
            yield root
            print(f'{root:.4f}', end=', ')
    print()
    print(f'Время счета по модулю timeit: ', timeit.timeit('dichotomy(0.0001,184,10000, 0.000001)', 'from __main__ import dichotomy'), 'seconds')
→ Ссылка