#White #Dark #txt #download

        
"""
Équivalences

Vous avez un code qui marche, et vous voulez le rendre plus joli, plus lisible.
C'est ce qu'on appelle du refactoring.

Voici une liste de transformations disponibles pour vous aider dans cette tâche.
Vous pouvez bien sûr choisir de faire la transformation ou non.

Un "→" indique que ce code sera probablement plus clair (selon moi).

Un "↔" indique que la clarté dépendra du contexte (il n'y en n'a pas un qui soit à priori plus clair).
"""

##
# inverser if/else 
##
if CONDITION:
    A
else:
    B
# ↔
if not(CONDITION):
    B
else:
    A

## exemple 1
if a == 5:
    print("hello")
else:
    waw = 2
# ↔ (inverser if/else)
if not(a == 5):
    waw = 2
else:
    print("hello")
# ↔ (not == ↔ !=)
if a != 5:
    waw = 2
else:
    print("hello")

###
# sinon ne rien faire
###
if CONDITION:
    A
else:
    pass  # ne rien faire
# → 
if CONDITION:
    A

## exemple 1
if a != 5:
    print("hello")
else:
    pass  # ne rien faire
# → ("sinon ne rien faire" est inutile)
if a != 5:
    print("hello")

## exemple 2
if a == 5:
    pass  # ne rien faire
else:
    print("hello")
# → (inverser if/else)
if a != 5:
    print("hello")
else:
    pass  # ne rien faire
# → ("sinon ne rien faire" est inutile)
if a != 5:
    print("hello")
    
###
# simplifier not (lois de De Morgan)
###
# De Morgan sur "et"
if not(A and B):
    ...
# ↔
if (not A) or (not B):
    ...

# De Morgan sur "ou"
if not(A or B):
    ...
# ↔
if (not A) and (not B):
    ...

## exemple 1
if not(a > 10 or a == 5):
    print('hello')
# → (De Morgan)
if a <= 10 and a != 5:
    print('hello')
    
## exemple 2
if a > 10 or a == 5:
    pass
else:
    print('hello')
# → (inverser if/else)
if not(a > 10 or a == 5):
    print('hello')
else:
    pass
# → ("sinon ne rien faire" est inutile)
if not(a > 10 or a == 5):
    print('hello')
# → (De Morgan)
if a <= 10 and a != 5:
    print('hello')

###
# if followed by if not
###
if a < b:
    print("hello")
if a >= b:
    print("tada")
# → (à condition que a et b ne soient pas modifiés dans le if !)
if a < b:
    print("hello")
else:
    print("tada")

###
# if variable 
###
if CONDITION:
    x = A
else:
    x = B
# →
x = A if CONDITION else B
# →
x = (A if CONDITION else B)
# →
x = (A if CONDITION else
     B)

## exemple
if a == 5:
    c = 2
else:
    c = 0
# → ("if en une ligne" aussi appelé "l'opérateur ternaire" ou le "if fonctionnel")
c = (5 if a == 5 else 0)
# ↔ (parenthèses non nécessaires)
c = 5 if a == 5 else 0

##
# if elif cascade on variable
##
if CONDITION:
    x = A
elif CONDITION_2:
    x = B
elif CONDITION_3:
    x = C
else:
    x = D
# → 
x = (A if CONDITION else
     B if CONDITION_2 else
     C if CONDITION_3 else
     D)

## exemple
if a == 5:
    c = 8
elif a == 2:
    c = 4
elif a < 0:
    c = 1
else:
    c = 0
# → (if fonctionnel)
c = (8 if a == 5 else
     4 if a == 2 else
     1 if a < 0 else
     0)

##
# renaming
##
#
# Vous pouvez renommer une variable pour lui donner un nom plus explicite :
e = v * t
i = e / 2.56
# →
distance = vitesse * temps
distance_pouces = distance / 2.56
# Généralement les noms de variables de quelques lettres sont <strong>trop court</strong>
# (sauf dans des expressions mathématiques ou des noms de variables connues comme le <code>"i"</code> dans une boucle)
# et des variables avec plus de trois vrais mots ont un nom <strong>trop long</strong>
# (un commentaire à la création de la variable sera sûrement plus clair).

## 
# inline variable
##
x = ...
operation(x)
# → (à condition que x n'est utilisé qu'une fois)
operation(...)
## exemple
x = taille + 1  # x dépend de la taille
y = taille - 1  # y dépend de la taille
le_coefficent = x + 2 * y  # on calcule le coefficent avec la formule linéaire
print(le_coefficent)       # on l'affiche

# ↔ (inline variable "le_coefficent")
x = taille + 1  # x dépend de la taille
y = taille - 1  # y dépend de la taille
print(x + 2 * y)  # on affiche le résultat de la formule linéaire

# ↔ (inline variables "x" and "y")
print((taille + 1) + 2 * (taille - 1))  # on affiche le résultat de la formule linéaire en fonction de la taille

##
# boolean return
##
def f(...):
    ...
    if CONDITION:
        return True
    else:
        return False
# →
def f(...):
    ...
    return CONDITION

## avec une variable
if CONDITION:
    res = True
else:
    res = False
# →
res = CONDITION

## exemple 1
def est_pair(x):
    if x % 2 == 0:    # si le reste de la division par deux vaut 0
        return True   # Vrai, le nombre est pair
    else:             # sinon
        return False  # Faux, le nombre n'est pas pair
# → (boolean return)
def est_pair(x):
    return x % 2 == 0  # x est pair ssi le reste de la division par deux vaut 0
# :
if est_pair(4):
    ...
    
## exemple 1'
if x % 2 == 0:   # si le reste de la division par deux vaut 0
    res = True   # le résultat est Vrai, le nombre est pair
else:            # sinon
    res = False  # le résultat est Faux, le nombre n'est pas pair
# → (boolean return)
res = (x % 2 == 0)  # le résultat est vrai ssi le reste de la division par deux vaut 0
# → (renaming)
est_pair = (x % 2 == 0)  # on nomme la variable de manière sémantique
# ↔ (parenthesis)
est_pair = x % 2 == 0  # parenthèses non nécessaires

## exemple 2
def voyelle(x):
    if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u':
        return True
    else:
        return False
# → (boolean return)
def voyelle(x):
    return x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u'  # x est une voyelle ssi x vaut 'a', 'e', 'i', 'o', ou 'u'
# :
if voyelle('a'):  # si 'a' est une voyelle
    ...

##
# == True 
##
# avec
def est_pair(x):
    if x % 2 == 0:  # si le reste de la division par deux vaut 0
        return True
    else:
        return False
# :
if est_pair(4) == True:  # si la fonction est_pair renvoie True
    ...
# →
if est_pair(4):  # si 4 est pair
    ...

##
# or
##
if CONDITION:
    A
elif CONDITION_2:
    A  # même A
# →
if CONDITION or CONDITION_2:
    A
    
## exemple
if a == 5:
    x = 2
elif a > 10:
    x = 2
# → (or)
if a == 5 or a > 10:
    x = 2
    
##
# or else
##
if CONDITION:
    A
elif CONDITION_2:
    A  # même A
else:
    B
# →
if CONDITION or CONDITION_2:
    A
else:
    B

## exemple
if a == 5:
    x = 2
elif a > 10:
    x = 2
else:
    print('error')
# → (or)
if a == 5 or a > 10:
    x = 2
else:
    print('error')

##
# or return
##
def f(...):
    ...
    if CONDITION:
        return True
    if CONDITION_2:
        return True
    return False
# →
def f(...):
    ...
    return CONDITION or CONDITION_2
# ↔
def f(...):
    ...
    return (CONDITION
            or CONDITION_2)

## exemple
def interessant(x):
    if x > 10:  # si x > 10
        return True  # il est intéressant
    if x == 5:  # si x == 5
        return True  # il est intéressant
    return False  # sinon, il n'est pas intéressant
# → (or return)
def interessant(x):
    return x > 10 or x == 5  # x est intéressant si il est > 10 ou == 5

##
# and
##
if CONDITION:
    if CONDITION_2:
        A
# →
if CONDITION and CONDITION_2:
    A

## exemple
if a == 5:
    if a > 10:
        print('waw')
# → (and)
if a == 5 and a > 10:
    print('waw')

##
# and else
##
if CONDITION:
    if CONDITION_2:
        A
    else:
        B
else:
    B  # même b
# →
if CONDITION and CONDITION_2:
    A
else:
    B

## exemple
if a == 5:
    if b > 10:
        waw = 2 
    else:
        print('error')
else:
    print('error')
# → (and)
if a == 5 and b > 10:
    waw = 2
else:
    print('error')

##
# if return
##
def f(...):
    ...
    if CONDITION:
        return X
    ...
# ↔
def f(...):
    ...
    if CONDITION:
        return X
    else:
        ...

## exemple
def f(x):
    if x < 0:
        return -1
    else:
        y = x + 2
        z = y ** 2
        return z
# → (if return)
def f(x):
    if x < 0:
        return -1
    y = x + 2
    z = y ** 2
    return z

# Je fais généralement ça quand le <code>"if"</code> est vraiment court comme un simple <code>"return"</code>.
# Souvent, ce sont des cas particuliers ou des cas de base, le code du bas est plus intéressant.

##
# for if return True (∃)
## for-if-return-True, any, exists, ∃ 
# Voici comment on code un "∃"
def f(...):
    ...
    for x in L:
        if condition:  # ce "if" n'a PAS de "else"
            return True
    return False
# → (en python, il y a "all")
def f(...):
    ...
    return any(condition for x in L)
# ↔
def f(...):
    ...
    return any(condition
               for x in L)

# Note: en python, il y a aussi le [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) mais peu de gens l'utilisent

## exemple
def contient_un_negatif(L):
    for x in L:  # pour tous les élements de la liste
        if x < 0:  # s'il est < 0
            return True  # la liste contient_un_negatif
    return False  # au final, c'est qu'elle n'en contient pas
# → (any)
def contient_un_negatif(L):
    return any(x < 0 for x in L)
# Qui se lira <em>Une liste L contient un négatif si</em>...
# <ul>
# <li> il y a un élément x < 0
# <li> il existe un x de L tel que x < 0
# <li> ∃ x ∈ L: x < 0
# </ul>

##
# for if return False (∀)
## for-if-return-False, all, forall, ∀
# Voici comment on code un "∀"
def f(...):
    ...
    for x in L:
        if condition:  # ce if n'a PAS de "else"
            return False
    return True
# → (en python, il y a "all")
def f(...):
    return all(not condition for x in L)
# ↔
def f(...):
    return all(not condition
               for x in L)

# Note: en python, il y a aussi le [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) mais peu de gens l'utilisent

## exemple
def totalement_positive(L):
    for x in L:  # pour tous les élements de la liste
        if x < 0:  # s'il est < 0
            return False  # la liste n'est pas totalement_positive
    return True  # au final, c'est que la liste est totalement_positive
# → (all)
def totalement_positive(L):
    return all(x >= 0 for x in L)
# Qui se lira <em>Une liste L est totalement_positive si</em>...
# <ul>
# <li> tous ses éléments x sont >= 0
# <li> pour tous les éléments x ∈ L on a x >= 0
# <li> quelque soit l'élément x ∈ L on a x >= 0
# <li> ∀ x ∈ L : x >= 0
# </ul>

##
# not ∀/∃ (lois de De Morgan)
## not-any, not-all
# De Morgan sur "∀"
not all(condition for x in L)
# →
any(not condition for x in L)

# De Morgan sur "∃"
not any(condition for x in L)
# →
all(not condition for x in L)

## exemple
if not all(x >= 0 for x in L):  # si on n'a pas tous les nombres >= 0
    ...
# → (if non empty)
if any(x < 0 for x in L):  # c'est qu'il existe un nombre < 0
    ...
# <strong>Attention</strong>: cette transformation ne marche pas si L est vide !
#

##
# for if return else return
##
# Voici comment on code une recherche linéaire
def f(...):
    for x in L:
        if condition:
            return a
    return b
# → (en python, il y a "next")
def f(...):
    return next((a for x in L if condition), b)
# ↔
def f(...):
    return next((a for x in L if condition),
                b)

# Note: en python, il y a aussi le [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) mais peu de gens l'utilisent

## exemple
#
# <em>Le super_nombre d'une liste est le <strong>premier</strong> x dans la liste tel que x > 10</em> :
def super_nombre(L):
    for x in L:  # pour tous les élements de la liste
        if x > 10:  # s'il est > 10
            return x  # c'est le super nombre de cette liste
    return 0  # il n'y a pas de super nombre, on renvoie 0
# →
def super_nombre(L):
    return next((x for x in L if x > 10), 0)

##
# for append
##
L = []
for x in iterable:
    L.append(e)
# →
L = [e for x in iterable]

##
# for append f(x)
## +, map
L = []
for x in iterable:
    L.append(f(x))
# →
L = list(map(f, iterable))
# ↔
L = [f(x) for x in iterable]

##
# for if append
## 
L = []
for x in iterable:
    if condition:
        L.append(e)
# →
L = [e for x in iterable if condition]

##
# for if f(x) append x
## +, filter
L = []
for x in iterable:
    if f(x):
        L.append(x)
# →
L = list(filter(f, iterable))
# ↔
L = [x for x in iterable if f(x)]

##
# itérer un générateur (python)
##
for x in list(generateur):
    ...
# →
for x in generateur:
    ...

## exemple 1
for x in list(map(f, L)):  # map, filter, zip...
    ...
# →
for x in map(f, L):
    ...

## exemple 2
# avec
def operation(x):
    return (x + 1) * 2 - x
# :
for x in list(map(operation, [1,2,3])):
    print(x)
# →
for x in map(operation, [1,2,3]):
    print(x)

##
# sum
##

## exemple
s = 0
for x in L:
    s += a
# → (sum)
s = sum(a for x in L)

# techniquement, "sum" est un cas particulier de "reduce" mais "reduce" est peu utile en python

##
# join
##

## exemple
s = ''
for x in L:
    s += a
# → (join)
s = ''.join(a for x in L)

# techniquement, "join" est un cas particulier de "reduce" mais "reduce" est peu utile en python

##
# in tuple (python)
##

## exemple
if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u':
    ...
# → (in)
if x in ('a', 'e', 'i', 'o', 'u'):
    ...

# c'est un cas particulier de recherche linéaire dans une liste