""" Equivalences You have a working code, and you want it to be more clean, more pretty, more readable. This is what we call, refactoring. Here is a list of transformation to help you in this task. You can of course choose to apply the transformation or not. A "→" means the code will probably be more readable (according to me). A "↔" means the clarity will depend on the context (neither code is a priori more readable). """ ## # inverser if/else ## if CONDITION: A else: B # ↔ if not(CONDITION): B else: A ## example 1 if a == 5: print("hello") else: waw = 2 # ↔ (invert if/else) if not(a == 5): waw = 2 else: print("hello") # ↔ (not == ↔ !=) if a != 5: waw = 2 else: print("hello") ### # else do nothing ### if CONDITION: A else: pass # do nothing # → if CONDITION: A ## example 1 if a != 5: print("hello") else: pass # do nothing # → ("else do nothing" is useless) if a != 5: print("hello") ## example 2 if a == 5: pass # do nothing else: print("hello") # → (invert if/else) if a != 5: print("hello") else: pass # do nothing # → ("else do nothing" is useless) if a != 5: print("hello") ### # simplify not (De Morgan's laws) ### # De Morgan on "and" if not(A and B): ... # ↔ if (not A) or (not B): ... # De Morgan on "or" if not(A or B): ... # ↔ if (not A) and (not B): ... ## example 1 if not(a > 10 or a == 5): print('hello') # → (De Morgan) if a <= 10 and a != 5: print('hello') ## example 2 if a > 10 or a == 5: pass else: print('hello') # → (invert if/else) if not(a > 10 or a == 5): print('hello') else: pass # → ("else do nothing" is useless) 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) ## example if a == 5: c = 2 else: c = 0 # → ("one-line if" also called "ternary operator" or "functional if") c = (5 if a == 5 else 0) # ↔ (parenthesis are useless) 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) ## example if a == 5: c = 8 elif a == 2: c = 4 elif a < 0: c = 1 else: c = 0 # → (functional if) c = (8 if a == 5 else 4 if a == 2 else 1 if a < 0 else 0) ## # renaming ## # # You can rename a variable to give it a name more explicit : e = v * t i = e / 2.56 # → distance = velocity * time distance_inch = distance / 2.56 # Generally variable names of few letters are too short # (except in mathematical expressions or well known variable names like the `"i"` in a loop) # and variable names with more than three real words are too long # (a comment next to the variable creation will be probably better). ## # inline variable ## x = ... operation(x) # → (only possible if x is used only once) operation(...) ## example x = size + 1 # x depends on the size y = size - 1 # y depends on the size the_coefficent = x + 2 * y # let's compute the coefficent using the linear formula print(the_coefficent) # let's print it # ↔ (inline variable "the_coefficent") x = size + 1 # x depends on the size y = size - 1 # y depends on the size print(x + 2 * y) # let's print the result of the linear formula # ↔ (inline variables "x" and "y") print((size + 1) + 2 * (size - 1)) # let's print the result of the linear formula depending on the size ## # 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 ## example 1 def is_even(x): if x % 2 == 0: # if the rest of division by 2 is 0 return True # Vrai, le nombre est pair else: # sinon return False # Faux, le nombre n'est pas pair # → (boolean return) def is_even(x): return x % 2 == 0 # x is even iff the rest of division by 2 is 0 # : if is_even(4): ... ## example 1' if x % 2 == 0: # if the rest of division by 2 is 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) # the result is true iff the rest of division by 2 is 0 # → (renaming) is_even = (x % 2 == 0) # on nomme la variable de manière sémantique # ↔ (parenthesis) is_even = x % 2 == 0 # parenthèses non nécessaires ## example 2 def vowel(x): if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u': return True else: return False # → (boolean return) def vowel(x): return x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u' # x is a vowel iff x is 'a', 'e', 'i', 'o', 'u' # : if vowel('a'): # if 'a' is a vowel ... ## # == True ## # given def is_even(x): if x % 2 == 0: # if the rest of division by 2 is 0 return True else: return False # : if is_even(4) == True: # si the is_even function returns True ... # → if is_even(4): # if 4 is even ... ## # or ## if CONDITION: A elif CONDITION_2: A # same A # → if CONDITION or CONDITION_2: A ## example 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 # same A else: B # → if CONDITION or CONDITION_2: A else: B ## example 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) ## example def interesting(x): if x > 10: # if x > 10 return True # it's interesting if x == 5: # if x == 5 return True # it's interesting return False # otherwise, it's not interesting # → (or return) def interesting(x): return x > 10 or x == 5 # x is interesting if it's > 10 or 5 ## # and ## if CONDITION: if CONDITION_2: A # → if CONDITION and CONDITION_2: A ## example 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 # same b # → if CONDITION and CONDITION_2: A else: B ## example 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: ... ## example 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 # I generally do that when the `"if"` is really short like a simple `"return"`. # 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, ∃ # Here is how we code a "∃" def f(...): ... for x in L: if condition: # this "if" DOESN'T have a "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: in python there is also the [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) but not so much people use it ## example def contains_a_negative(L): for x in L: # for each element in the list if x < 0: # if it's < 0 return True # the list contains_a_negative return False # in the end, it means it doesn't contain one # → (any) def contains_a_negative(L): return any(x < 0 for x in L) # We'll read it as A list L contains_a_negative if... #
#
• there is a x < 0 #
• there exists any x such that x < 0 #
• ∃ x ∈ L: x < 0 #
## # for if return False (∀) ## for-if-return-False, all, forall, ∀ # Here is how we code a "∀" def f(...): ... for x in L: if condition: # this "if" DOESN'T have a "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: in python there is also the [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) but not so much people use it ## example def totally_positive(L): for x in L: # for each element in the list if x < 0: # if it's < 0 return False # the list is not totally_positive return True # in the end, the list is totally_positive # → (all) def totally_positive(L): return all(x >= 0 for x in L) # We'll read it as A list L is totalement_positive if... #
#
• A list is totally positive if all its elements x are >= 0 #
• for all its elements x one have x >= 0 #
• any element x ∈ L satisfies x >= 0 #
• ∀ x ∈ L : x >= 0 #
## # not ∀/∃ (De Morgan's laws) ## not-any, not-all # De Morgan on "∀" not all(condition for x in L) # → any(not condition for x in L) # De Morgan on "∃" not any(condition for x in L) # → all(not condition for x in L) ## example 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 ... # Attention: cette transformation ne marche pas si L est vide ! # ## # for if return else return ## # Here is how one code a linear search def f(...): for x in L: if condition: return a return b # → (in python, one can use "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: in python there is also the [for...else](https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops#9980752) but not so much people use it ## example # # Le super_nombre d'une liste est le premier x dans la liste tel que x > 10 : def super_number(L): for x in L: # for each element in the list if x > 10: # if it's > 10 return x # it's the super_number of that list return 0 # il n'y a pas de super nombre, on renvoie 0 # → def super_number(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)] ## # iterate a generator (python) ## for x in list(generator): ... # → for x in generator: ... ## example 1 for x in list(map(f, L)): # map, filter, zip... ... # → for x in map(f, L): ... ## example 2 # with 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 ## ## example s = 0 for x in L: s += a # → (sum) s = sum(a for x in L) # technically, "sum" is a particular case of "reduce" but "reduce" is a bit useless in python ## # join ## ## example s = '' for x in L: s += a # → (join) s = ''.join(a for x in L) # technically, "join" is a particular case of "reduce" but "reduce" is a bit useless in python ## # in tuple (python) ## ## example if x == 'a' or x == 'e' or x == 'i' or x == 'o' or x == 'u': ... # → (in) if x in ('a', 'e', 'i', 'o', 'u'): ... # it's a particular case of linear search in a list