try-except and the "analyze.py" statistics program.

This program and its accompanying module (at the end) demonstrate a number of features:

analyze.py


#!/usr/bin/env python3
# 2021-04-18
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 30 10:48:26 2021

"analyze.py" with try-except blocks

@author: rmontant
"""
import sys
import stats

def id(a):
    return a
#--------


def main(argv=[__name__]):
    if len(argv) == 3:
        filename_in = argv[1]
        filename_out = argv[2]
    else:
        filename_in = input('Data file to read? ')
        filename_out = input('Report file to write? ')

    if len(filename_in) == 0:
        return 1
    elif len(filename_out) == 0:
        filename_out = 'report.txt'


    try:
        inhandle = open(filename_in, 'r')
    except Exception as e:
        print("Couldn't open the filename for reading!\n")
        print('The error was: "{:s}"'.format(str(e)))
        return 2

    numbers = []
    for line in inhandle.readlines():
        pieces = line.split()
        for piece in pieces:
            #numbers.append( float(piece) )
            try:
                v = float(piece)
            except Exception as e:
                print(e)
                print('Line:', line)
                print('Piece:', piece)
                print('#--------\n\n')
            else:
                numbers.append(v)

    inhandle.close()

    strings = [
        'file {:s}\n',
        '{:12d} values',
        '{:12.3e} span',
        '{:12.3e} min',
        '{:12.3e} max',
        '{:12.3e} median',
        '{:12.3e} mean',
        '{:12.3e} std. dev.',
        '{:12.3e} geometric_mean'
        '{:12.3e} harmonic_mean'
    ]

    functions = [
        id,
        len,
        stats.span,
        min,
        max,
        stats.median,
        stats.mean,
        stats.stdev,
        stats.geometric_mean,
        stats.harmonic_mean
    ]

    reportlist = []
    for n in range(len(strings)):
        try:
            s = strings[n].format(functions[n](numbers))
        except ZeroDivisionError:
            print('Zero division in function', str(functions[n]))
        except Exception as e:
            print(e)
            print('Error in', str(functions[n]))
        else:
            reportlist.append(s)

    reportlist.append('#--------\n\n')


    outhandle = open(filename_out, 'a')
    outhandle.write( '\n'.join(reportlist) )
    outhandle.close()

    print( '\n'.join(reportlist) )
#--------

if __name__ == '__main__':
    sys.exit(main(sys.argv))
#--------

stats.py

# -*- coding: utf-8 -*-
"""
Created on Fri Mar 26 11:15:25 2021

Module for descriptive statistics
2021-04-18 v1.1 implement harmonic()
 
@author: rmontant
"""

def mean(datalist):
    return sum(datalist) / len(datalist)
#--------

def median(datalist):
    sdl = sorted(datalist)
    length = len(sdl)
    indexUpper = length // 2    # INTEGER division !
    if length % 2 == 1:
        medianValue = sdl[ indexUpper ]
    else:
        indexLower = indexUpper - 1
        medianValue = (sdl[ indexUpper ] + sdl[ indexLower ]) / 2
    return medianValue
#--------

def geometric_mean(datalist):
    from math import prod
    p = prod(datalist)
    return p ** (1/len(datalist))
#--------

def harmonic_mean(datalist):
    sum_inverses = sum( [ 1/x  for x in datalist ] )
    return len(datalist) / sum_inverses
#--------

def span(datalist):
    return max(datalist) - min(datalist)
#--------

def variance(datalist):
    n = len(datalist)
    ssq = sum( [x**2 for x in datalist] )
    sqs = sum(datalist)**2
    return (ssq - sqs/n) / (n - 1)
#--------

def stdev(datalist):
    return variance(datalist)**0.5
#--------