Hello guys ! I’ve been coding a project on my own about statistics. I used OOP (or I think it is). It is about calculate statistics with some data that are all provided by users (that cannot understand code or only a little). I have a huge bug in the graph and table (and maybe others, but I didn’t see it) section : it works fine if I print it by hand, but it crashes when I use the user system. It seems the problem comes from the key turning from it initial state to ‘O’, but I don’t see any fix right now. I know that the common point is the self.dict[value] use but I don’t see any efficient way to replace it (and also it is intended to be a user-provided value, so…) Could you help me please ?
class Stats() :
def __init__(self, dicts: dict, name):
self.name = name
self.dict = dicts
self.effectif = sum(self.dict.values())
#_______METHODS__________
def last(self, list):
return list[len(list) - 1]
def odd_or_even(self, number):
odd = [1, 3, 5, 7, 9]
even = [0, 2, 4, 6, 8]
for a in str(number) :
num = int(a)
if num in odd :
return 1
elif num in even :
return 0
def get_frequence(self, value):
if not value in self.dict.keys() :
return f"La variable {value} n'existe pas."
effective = self.dict[value]
result = int((effective / self.get_effectif)*100) if ((effective / self.get_effectif)*100) % 1 == 0 else (effective / self.get_effectif)*100
return f'{result} %'
def get_frequence_nbr(self, value):
if not value in self.dict.keys():
return f"The value {value} doesn't exist."
effective = self.dict[value]
result = int((effective / self.get_effectif)*100) if ((effective / self.get_effectif)*100) % 1 == 0 else (effective / self.get_effectif)*100
return result
#___________________GETTERS______________________
@property
def get_table(self):
already = []
is_val_1 = None
top_row_1 = ''
vals_row_1 = ''
bot_row_1 = ''
vals_row_2 = ''
bot_row_2 = ''
val_1 = self.name
val_2 = 'Effectifs'
if len(str(val_1)) > len(str(val_2)):
size = len(str(val_1))
text_1 = '| ' + str(val_1) + ' |'
is_val_1 = True
else:
size = len(str(val_2))
text_2 = '| ' + str(val_2) + ' |'
line = '+' + '-' * size + 2 * '-' + '+'
if is_val_1:
text_2 = '| ' + (size - len(str(val_2))) // 2 * ' ' + ' ' + str(val_2) + (size - len(str(val_2))) // 2 * ' ' + ' ' + '|'
else:
text_1 = '| ' +(size - len(str(val_1))) // 2 * ' ' + ' ' + str(val_1) + (size - len(str(val_1))) // 2 * ' ' + ' ' + '|'
top_row_1 += line
bot_row_1 += line
bot_row_2 += line
vals_row_1 += text_1
vals_row_2 += text_2
val_1 = None
val_2 = None
for column in self.get_sorted :
if column in already :
continue
text_1 = ''
text_2 = ''
is_val_1 = False
val_1 = column
already.append(val_1)
val_2 = self.dict[column]
if len(str(val_1)) > len(str(val_2)) :
size = len(str(val_1))
text_1 = ' ' + str(val_1) + ' |'
is_val_1 = True
else :
size = len(str(val_2))
text_2 = ' ' + str(val_2) + ' |'
line = '-' * size + 2 * '-' + '+'
if is_val_1 :
text_2 = (size - len(str(val_2))) // 2 * ' ' + ' ' + str(val_2) + (size - len(str(val_2))) // 2 * ' ' + ' ' + '|'
else :
text_1 = (size - len(str(val_1))) // 2 * ' ' + ' ' + str(val_1) + (size - len(str(val_1))) // 2 * ' ' + ' ' + '|'
top_row_1 += line
bot_row_1 += line
bot_row_2 += line
vals_row_1 += text_1
vals_row_2 += text_2
row_1 = '\n' + top_row_1 + '\n' + vals_row_1 + '\n' + bot_row_1 + '\n'
row_2 = vals_row_2 + '\n' + bot_row_2 + '\n'
return (row_1 + row_2)
@property
def get_dict(self):
return self.dict
@property
def get_array(self):
result = []
for key, value in self.dict.items():
result += [key] * value
return result
@property
def get_effectif(self):
return self.effectif
@property
def get_sorted(self):
for val in self.get_array :
if not isinstance(val, (int, float)) :
return "On ne peut pas faire cette opération ! Les valeurs données ne sont pas des nombres."
return sorted(self.get_array)
@property
def get_moyenne(self):
for val in self.get_array :
if not isinstance(val, (int, float)) :
return "On ne peut pas faire cette opération ! Les valeurs données ne sont pas des nombres."
sum_of_all = sum(self.get_array)
return sum_of_all / self.get_effectif
@property
def get_mediane(self):
for val in self.get_sorted :
if not isinstance(val, (int, float)) :
return "On ne peut pas faire cette opération ! Les valeurs données ne sont pas des nombres."
list = self.get_sorted
if self.odd_or_even(self.get_effectif) :
middle = (len(list) // 2) - 1
return list[middle]
else :
middles = [(len(list) // 2) - 1, len(list) // 2]
result = (list[middle[0]] + list[middle[1]]) / 2
@property
def get_étendue(self):
for val in self.get_sorted :
if not isinstance(val, (int, float)) :
return "On ne peut pas faire cette opération ! Les valeurs données ne sont pas des nombres."
min_val = self.get_sorted[0]
max_val = self.last(self.get_sorted)
return max_val - min_val
@property
def get_graph(self):
already = []
result = ' ↑\n'
max_leg = 0
arrow_h = ''
leg_h = ''
for column in self.get_sorted :
if column in already :
continue
val = column
already.append(val)
print(already)
print(val)
val_eff = self.dict[val]
print(val_eff)
if val_eff > max_leg :
max_leg = val_eff
arrow_h += '---|'
leg_h += f' {val}'
for legende, column in zip(range(max_leg, -1, -1), self.get_sorted) :
already_1 = []
added = f'{legende} |'
for col in self.get_sorted :
if col in already_1 :
continue
val = col
val_eff = self.dict[val]
already_1.append(val)
print(val)
print(val_eff)
added += ' '
if val_eff >= legende :
added += 'o'
else :
added += ' '
if legende > 0 :
result += added + '\n'
else :
result += added
arrow_h += '--→\n'
leg_h = ' ' + leg_h
result += '\n |' + arrow_h + leg_h
return result
def ajouter(dicti) :
added_key = None
while not added_key :
added_key = input('Quel est la valeur de la variable ajoutée ?' + '\n→')
if not added_key :
print('Merci de ne pas ajouter de variable vide.')
if added_key in dicti.keys() :
print('La variable existe déjà.')
ajouter(dicti)
passed = False
while not passed :
passed_ = False
added_eff = input("Quel est l'effectif de la variable ajoutée ?"+ '\n→')
is_float = False
for car in added_eff :
if car not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.'] :
print('Ajouter seulement des nombres en effectif et séparer les virgules avec un point.')
passed_ = True
break
if car == '.' :
is_float = True
if passed_ :
continue
else :
passed = True
if is_float :
added_eff = float(added_eff)
else :
added_eff = int(added_eff)
dicti[added_key] = added_eff
return 'La variable a été ajoutée !'
def montrer(stat) :
commande = input('\nQue voulez vous faire ? (écrire "aide" pour voir la liste)'+ '\n→')
commande = commande.lower()
commandes = ['aide', 'dictionnaire', 'liste' ,'effectif' ,'triée' ,'moyenne' ,'médiane' ,'étendue' ,'fréquence' ,'tableau' ,'graphique' ,'ajouter' ,'changer' ,'supprimer', 'arrêter']
if commande not in commandes :
return('Cette commande n\'est pas acceptée. (écrire "aide" pour voir la liste des commandes)')
if commande == 'aide' :
return "\n-Montrer les valeurs (dictionnaire) : dictionnaire\n-Montrer les valeurs (liste) : liste\n-Montrer l'effectif total : effectif\n-Montrer la liste triée : triée\n-Montrer la moyenne : moyenne\n-Montrer la médiane : médiane\n-Montrer l'étendue : étendue\n-Montrer la fréquence d'une variable (en pourcentages) : fréquence\n-Montrer un tableau : tableau\n-Montrer un graphique : graphique\n\n-Ajouter une variable : ajouter\n-Changer une variable : changer_var\n-Supprimer une variable : supprimer\n-Changer le nom : changer_nom\n-Arrêter le programme (!ATTENTION! : cette action est irréversible !) : arrêter"
if commande == 'dictionnaire' :
return stat.get_dict
if commande == 'liste' :
return stat.get_array
if commande == 'effectif' :
return stat.get_effectif
if commande == 'triée' :
return stat.get_sorted
if commande == 'moyenne' :
return stat.get_moyenne
if commande == 'médiane':
return stat.get_mediane
if commande == 'étendue' :
return stat.get_etendue
if commande == 'fréquence' :
var = input('De quelle variable voulez-vous voir la fréquence ?'+ '\n→')
if stat.get_frequence != f"La variable {var} n'existe pas." :
return 'La fréquence de var est de :', stat.get_frequence(var)
else :
return stat.get_frequence(var)
if commande == 'tableau' :
return stat.get_table
if commande == 'graphique' :
return stat.get_graph
if commande == 'ajouter' :
dict = stat.dict
ajouter(dict)
stat = Stats(dict, stat.name)
if commande == 'changer' :
var = input('Quelle variable voulez-vous modifier ?'+ '\n→')
if var not in stat.get_dict.keys() :
return "la variable n'existe pas."
else :
n_var_key = ''
n_var_val = ''
n_var_key_O = input('Modifier le nom ? O/N'+ '\n→')
if n_var_key_O == 'O' :
n_var_key = input('écrire le nouveau nom.'+ '\n→')
else :
n_var_key = var
n_var_val_O = input('Modifier la valeur ? O/N'+ '\n→')
if n_var_val_O == 'O' :
n_var_val = input('écrire la nouvelle valeur.'+ '\n→')
else :
n_var_val = stat.dict[var]
stat.dict.update(n_var_key, n_var_val)
return 'La variable a été modifiée !'
if commande == 'supprimer' :
var = input('Quelle variable voulez-vous supprimer ?'+ '\n→')
if var not in stat.get_dict.keys() :
return "la variable n'existe pas."
else :
del stat.dict[val]
return 'La variable a été supprimée !'
if commande == 'arrêter' :
broke = True
print('Arrêt en cours ...')
return
broke = False
def debut() :
global broke
name = input('Que sont les variables ajoutées ? (de quel type)'+ '\n→')
values = {}
print('Commençons par ajouter une variable.\n')
ajouter(values)
while not broke :
print(montrer(Stats(values, name)))
print(Stats({
1: 2,
2: 5
}, 'd').get_graph)
debut()
By the way the text is in French because I’m French and I know there are tools to display some graphs but I don’t want to use them because I want it to be only with things I know and fully displayable on the terminal.