Comment ne pas répéter des portions de code ?

Résolu/Fermé
Louis-Fiacre - 22 mars 2021 à 16:13
Louis-Fiacre Messages postés 2 Date d'inscription mardi 23 mars 2021 Statut Membre Dernière intervention 24 mars 2021 - 24 mars 2021 à 10:02
Bonjour,
Je suis débutant en python et j'aimerais avoir une relecture critique de mon petit script. J'ai trois problèmes : je déclare des variables globales mais je ne sais pas si dans mon script c'est nécessaire où si je peux faire d'une autre manière. Je répète du code dans ma fonction decode() mais là aussi je ne sais pas comment simplifier la tache, je n'est même pas le début d'une idée. Et enfin ma gestion des arguments optionnels de la ligne de commande dans main() me paraissent pas pro. Je mets le code complet à la fin de mon poste. Je vous remercie du temps que vous me consacrerez. Et j'ai vraiment envie d'apprendre de vos remarques et explications.
Bien cordialement,

Louis-Fiacre

# -*- coding: utf-8 -*-
from collections import Counter
import sys, getopt

global ordered_french_dico
french_dico = dict() # issu de https://www.apprendre-en-ligne.net/crypto/stat/francais.html
french_dico = {'a': 8.15, 'b': 0.97, 'c': 3.15, 'd': 3.73, 'e': 17.39, 'f': 1.12, 'g': 0.97, 'h': 0.85, 'i': 7.31, 'j': 0.45, 'k': 0.02, 'l': 5.69, 'm': 2.87, 'n': 7.12, 'o': 5.28, 'p': 2.80, 'q': 1.21, 'r': 6.64, 's': 8.14, 't': 7.22, 'u': 6.38, 'v': 1.64, 'w': 0.03, 'x': 0.41, 'y': 0.28, 'z': 0.15,}
ordered_french_dico = sorted(french_dico.items(), key=lambda x: x[1], reverse = True) #valeurs décroissantes
global ordered_english_dico
english_dico = dict() # issu de https://www.apprendre-en-ligne.net/crypto/stat/anglais.html
english_dico = {'a': 8.08, 'b': 1.67, 'c': 3.18, 'd': 3.99, 'e': 12.56, 'f': 2.17, 'g': 1.80, 'h': 5.27, 'i': 7.24, 'j': 0.14, 'k': 0.63, 'l': 4.04, 'm': 2.60, 'n': 7.38, 'o': 7.47, 'p': 1.91, 'q': 0.09, 'r': 6.42, 's': 6.59, 't': 9.15, 'u': 2.79, 'v': 1.00, 'w': 1.89, 'x': 0.21, 'y': 1.65, 'z': 0.07,}
ordered_english_dico = sorted(english_dico.items(), key=lambda x: x[1], reverse = True) #valeurs décroissantes
global ordered_italian_dico
italian_dico = dict() # issu de https://fr.sttmedia.com/frequences-de-lettres-italien
italian_dico = {'a': 11.00, 'b': 1.05, 'c': 4.30, 'd': 3.39, 'e': 11.97, 'f': 1.01, 'g': 1.65, 'h': 1.43, 'i': 10.27, 'j': 0.00, 'k': 0.00, 'l': 5.70, 'm': 2.87, 'n': 7.02, 'o': 10.08, 'p': 2.96, 'q': 0.45, 'r': 6.19, 's': 5.48, 't': 6.97, 'u': 3.28, 'v': 1.75, 'w': 0.00, 'x': 0.00, 'y': 0.00, 'z': 0.85,}
ordered_italian_dico = sorted(italian_dico.items(), key=lambda x: x[1], reverse = True) #valeurs décroissantes
global freq
freq = dict()
global alpha
alpha = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']

def sorti(src_in, decal): #fonction de substitution des caractères
list_decal = []
for car in src_in:
upper = False
if car not in alpha:
if car.isupper() == False:
car_decal = car

if car.isupper() == True:
car = car.lower()
upper = True
if car in alpha:
ide = (alpha.index(car) + decal)
while ide >= len(alpha):
ide = ide - len(alpha)
car_decal = alpha[ide]
if upper == True:
car_decal = car_decal.upper()

list_decal.append(car_decal)
text_decal = "".join(list_decal)

print("[!] Texte sorti : \n",text_decal)
return text_decal

def taux(a, b): #donne taux de différence entre frequence des caractères de la source et d'un dictionnaire de référence
somme_score = 0
score = []
for i in range(0,len(a)):
taux = (a[i][1] - b[i][1])
if taux < 0:
taux = taux * (-1)
score.append(taux)
somme_score = sum(score)/len(score)
return somme_score

def pretraitement(text_0):
text = text_0.lower()
text = text.replace(",", "")
text = text.replace("'", "")
text = text.replace(" ", "")
text = text.replace("\n", "")
return text

def read(src_in): #extrait la source et renvoie une chaine de caractère
try:
source = open(src_in, "r")
text_0 = "".join(source.readlines())# passe d'une list à une chaine de caracrère
print("[!] Texte source :\n",text_0)
finally:
source.close()
return text_0

def write(src_out, text_decal): # ecrit le text de sorti dans un nouveau fichier
try:
source = open(src_out, "a")
source.write(text_decal)
print("[!] Texte de sorti dans: ", src_out)
finally:
source.close
return True

def code(src_in, decal, src_out = ""):
decal = int(decal)
text_0 = read(src_in)
print("[!] Substitution par ",decal," lettres")
text_out = sorti(text_0, decal)
if src_out != "":
write(src_out, text_out)

def decode(src_in, src_out = ""):
text_0 = read(src_in)
text = pretraitement(text_0)
length_text = len(text) #longueur du texte
occur = Counter(text) # occurence de chaque caractère
for (key, value) in occur.items():
pourcent = round((value / length_text)*100, 2)
freq[key] = pourcent # frequence de pourcentage des occurences
alpha_freq = sorted(freq.items(), key=lambda x: x[0]) #alphabétique
value_freq = sorted(freq.items(), key=lambda x: x[1], reverse = True) #valeurs décroissantes
FR = taux(value_freq, ordered_french_dico)
ANG = taux(value_freq, ordered_english_dico)
IT = taux(value_freq, ordered_italian_dico)

if FR < ANG and FR < IT:
print("[!] Texte source de ",length_text,"caractères en français")
decal = alpha.index(ordered_french_dico[0][0]) - alpha.index(value_freq[0][0])
print("[!] Lettre ",value_freq[0][0],"=",ordered_french_dico[0][0],"Substitution par ",decal," lettres")

elif ANG < FR and ANG < IT:
print("[!] Texte source de ",length_text,"caractères en anglais")
decal = alpha.index(ordered_english_dico[0][0]) - alpha.index(value_freq[0][0])
print("[!] Lettre ",value_freq[0][0],"=",ordered_english_dico[0][0],"Substitution par ",decal," lettres")

elif IT < FR and IT < ANG:
print("[!] Texte source de ",length_text,"caractères en italien")
decal = alpha.index(ordered_italian_dico[0][0]) - alpha.index(value_freq[0][0])
print("[!] Lettre ",value_freq[0][0],"=",ordered_italian_dico[0][0],"Substitution par ",decal," lettres")
text_out = sorti(text_0, decal)
if src_out != "":
print(text_out)
write(src_out, text_out)

def usage():
print("[!] Script pour coder et decoder un texte par substitution de lettre\n",
" --decode ou -d attend un argument obligatoire [fichier_source.txt] et un argument optionnel [fichier_out.txt]\n",
" --code ou -c attend deux arguments obligatoires [fichier_source.txt] [integer] et un argument optionnel [fichier_out.txt]\n",
" --help ou -h Affiche les commandes possibles")

def main(argv):
try:
opts, args = getopt.getopt(argv, "hdc",["help", "decode","code"])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
print(opt, arg)
if opt in ("-h", "--help"):
print(arg)
usage()
sys.exit()
elif opt in ("-d", "--decode"):
try: src_out = argv[2]
except: src_out = ""
decode(argv[1],src_out)
elif opt in ("-c", "--code"):
try: src_out = argv[3]
except: src_out = ""
code(argv[1], argv[2], src_out)

if __name__ == "__main__":
main(sys.argv[1:])
A voir également:

1 réponse

yg_be Messages postés 22730 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 avril 2024 1 477
22 mars 2021 à 16:52
bonjour,
il est utile de préciser le langage quand tu utilises les balises de code. explications ici: https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code

à propos de decode():
1) ne manque t'il pas un else? que doit faire le programme si aucune des trois conditions n'ait satisfaite?
2) comment simplifier et éviter de recopier du code: commence par identifier clairement ce qui change et ce qui ne change pas.
1
Merci pour vos remarques, oui j'ai vu qu'on pouvais choisir le langage pour les balises dans un menu déroulant, j'ai été trop vite.
Oui merci, je rajoute un else pour proprement dire qu'il ne reconnait pas la langue d'origine et mettre fin au script même si avec les conditions actuels il y aura toujours un des trois selectionnés.
Alors c'est là où je sèche. J'ai bien compris ce qui est récurrent, et donc j'ai deux infos FR et ordered_french_dico[0][0] et leur variantes dans les autres langues mais dois-je faire une boucle for avec un dico ['FR':'0.23','ANG':'0.52', etc] et un dico ['FR':'ordered_french_dico',etc] ? Je vous remercie du temps que vous m'accordez.
0
yg_be Messages postés 22730 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 avril 2024 1 477 > Louis-Fiacre
Modifié le 22 mars 2021 à 17:46
dans decode, il s'agit bien du else dans le cas où aucune des conditions n'est remplie:
FR < ANG and FR < IT:
ANG < FR and ANG < IT:
IT < FR and IT < ANG:

il me semble indispensable d'avoir un else, pour éviter des erreurs dans la suite du code.

commence par écrire ce que tu as compris qui était récurrent.
à titre d'exemple, voilà comment je montrerais ce qui est récurrent tout au début du programme, où tu fais également trois fois plus ou moins la même chose:
global <gras>ordered_french_dico
dico = dict()
dico = {'a': 8.15, 'b': 0.97, 'c': 3.15, 'd': 3.73, 'e': 17.39, 'f': 1.12, 'g': 0.97, 'h': 0.85, 'i': 7.31, 'j': 0.45, 'k': 0.02, 'l': 5.69, 'm': 2.87, 'n': 7.12, 'o': 5.28, 'p': 2.80, 'q': 1.21, 'r': 6.64, 's': 8.14, 't': 7.22, 'u': 6.38, 'v': 1.64, 'w': 0.03, 'x': 0.41, 'y': 0.28, 'z': 0.15,}
ordered_french_dico = sorted(dico.items(), key=lambda x: x[1], reverse = True)

ainsi, on peut voir clairement ce qui change et ce qu'il faut traiter si on veut simplifier.

fais de même pour les instructions simplifiables dans decode().
0
Louis-Fiacre > yg_be Messages postés 22730 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 avril 2024
Modifié le 22 mars 2021 à 18:28
Je vous suis alors pour :
if FR < ANG and FR < IT:
        print("[!] Texte source de ",length_text,"caractères en français")
        decal = alpha.index(ordered_french_dico[0][0]) - alpha.index(value_freq[0][0])
        print("[!] Lettre ",value_freq[0][0],"=",ordered_french_dico[0][0],"Substitution par ",decal," lettres")

if FR < ANG and FR < IT:
print("[!] Texte source de ",length_text,"caractères en français")
decal = alpha.index(ordered_french_dico[0][0]) - alpha.index(value_freq[0][0])
print("[!] Lettre ",value_freq[0][0],"=",ordered_french_dico[0][0],"Substitution par ",decal," lettres")
Mais si je fais une fonction decal comme :
def decal(dico, lang)
        print("[!] Texte source de ",length_text,"caractères en ", lang)
        decal = alpha.index(dico[0][0]) - alpha.index(value_freq[0][0])
        print("[!] Lettre ",value_freq[0][0],"=",dico[0][0],"Substitution par ",decal," lettres") 

Je n'ai pas l'impression de simplifier tant que ca et simplifier plus haut avec
if FR < ANG and FR < IT:
me paraît hors de ma portée. Je ne vois pas comment créer un lien entre FR ANG IT, avec un liste ? Je vous remercie de toutes vos explications
0
yg_be Messages postés 22730 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 avril 2024 1 477 > Louis-Fiacre
Modifié le 22 mars 2021 à 18:48
tu ne montres pas comment tu proposes d'utiliser la fonction decal().

tu parles de simplifier. tant que tu n'as que trois langues, ce c'est pas très utile. moi j'essaierais de généraliser, afin, si nécessaire, de pouvoir gérer un plus grand nombre de langues.
si tu veux faire cela, il me semble nécessaire de commencer par utiliser des noms de variables génériques, donc supprimer les noms spécifiques tels que ordered_french_dico et FR.
0
Louis-Fiacre > yg_be Messages postés 22730 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 avril 2024
Modifié le 22 mars 2021 à 19:04
Oui je crois que j'atteins une limite dans ma compréhension de python. J'aimerais justement généraliser comme tu dis pour un nombre x de langue. Mais je ne vois pas comment faire dès la déclaration des différents dictionnaires. Si je fais un fichier texte avec un nom de langue, un dictionnaire et une variable de taux par ligne ca serait une solution ?
Où alors dois-je me tourner vers une déclaration de classe définie par un nom de langue, un dictionnaire et une variable de taux ?
0