Les instructions composées

Les instructions composées

Jusqu'ici nos programmes étaient une suite d'instructions et s'exécutaient inlassablement de haut en bas :

instruction 1
instruction 2
instruction 3
... 

L'ordinateur lisait les instructions une à une et effectuait la tâche demandée. Ce n'est pas très intéressant ni pour lui ni pour nous, et heureusement il est possible de casser cette monotonie avec les instructions composées.

Les instructions composées sont des procédures qui agissent sur un ensemble d'instructions simples : le bloc d'instructions. Elles se présentent sous cette forme :

instruction composée :
    instruction 1
    instruction 2
    ... 

La déclaration de l'instruction composée se termine par deux points et toutes les instructions sur lesquelles elle agit sont sous elle, décalées d'une tabulation par rapport à elle. Je marque ce dernier point car le grand intérêt des instructions composées c'est de pouvoir s'emboiter à l'infini :

instruction 1
instruction composée 1 :
    instruction 2
    instruction 3
    instruction composée 2 :
        instruction 4
    instruction 5
instruction 6 

Ici l'instruction composée 1 comprends les instructions 2 et 3 mais aussi l'instruction composée 2 et l'instruction 5, qui sont toutes sous elle et décalées d'une tabulation. L'instruction 4 est comprise dans l'instruction composée 2 et doit donc être décalée de deux tabulations. Les instructions 1 et 6 ne font quand à elle parti d'aucune instruction composées : l'instruction 1 car elle est située au-dessus de la déclaration de l'instruction composée 1, et l'instruction 6 car elle n'est pas décalée d'une tabulation.

Les instructions conditionnelles permettent comme leur nom l'indique de faire une action sous certaines conditions.

Les conditions

Booléens

Un booléen est un type de valeur, à l'instar des entiers ou des tableaux. Sa caractéristique est de ne pouvoir prendre que deux valeurs : soit True (vrai) soit False (faux).

On peut répondre à une condition directement avec un booléen :

condition = True
print condition # la condition est vraie
 
condition = False
print condition # la condition est fausse

Opérateurs de comparaison

Il est possible de comparer deux valeurs au moyen d'opérateurs de comparaison. Ces opérateurs, contrairement aux opérateurs d'affectation, ne font que retourner le résultat de la comparaison, sans modifier les valeurs.

Par exemple, pour comparer si deux valeurs sont égales, on utilise l'opérateur “==” :

print 5 == 2     # False
print 5 == 5     # True
print 5 == 5.5   # False
print 5 == 5.0   # True
print 'a' == 'b' # False
print 'a' == 'a' # True

Pour comparer si une valeur est supérieure à une autre, on utilise l'opérateur “>” :

print 5 > 2     # True
print 5 > 5     # False
print 5.5 > 5   # True
print 5 > 5.0   # False

Une liste des opérateurs est disponible ici.

Comme on peut le constater, le résultat d'une comparaison est un booléen : une comparaison est donc soit vraie, soit fausse.

On peut comparer tous les types de valeurs, toutefois certains résultats auront peu de sens : le mot tomate est-il supérieur à 2.5 ?

Conditions multiples avec les opérateurs logiques

Il est possible de faire des conditions plus complexes à l'aide des opérateurs logiques and, or et not.

On peut dire par exemple:

La condition n'est vraie que si x est supérieur à 10 et si y est inférieur à 5 :

print 75 > 10 and 4 < 5 # True
print 75 > 10 and 6 < 5 # False

La condition n'est vraie que si x est supérieur à 0 et inférieur à 20 :

print 2 > 0 and 2 < 20   # True
print 33 > 0 and 33 < 20 # False

On peut dans ce cas écrire :

0 < x < 20

La condition est vraie si x est supérieur à 0 ou si y est égal à 5 :

print 5 > 0 or 6 == 5 # True
print 0 > 0 or 6 == 5 # False

La condition n'est vraie que si x n'est pas supérieur à y :

print not 5 > 7 # True
print not 8 > 7 # False

L'instruction if...elif...else

L'instruction if…elif…else permet de n'exécuter un ensemble d'instructions que sous certaines conditions.

On écrit, au minimum :

if condition :
    instruction 1
    instruction 2   
    ...

Le mot clé if indique qu'il s'agit d'une instruction conditionnelle. Si la condition est vraie, le bloc d'instruction sera exécuté.

Il est possible de faire suivre une instruction if d'une instruction else :

if condition :
    instruction 1
    instruction 2
else :
    instruction 3

Si la condition est vraie, les instructions 1 et 2 seront exécutées, sinon c'est l'instruction 3 qui sera exécutée.

Il est aussi possible d'utiliser l'instruction elif, contraction de else if :

if condition 1 :
    instruction 1
    instruction 2
elif condition 2 :
    instruction 3
else :
    instruction 4

Si la condition 1 est vraie, les instructions 1 et 2 seront exécutées, sinon si la condition 2 est vraie, l'instruction 3 sera exécutée, sinon c'est l'instruction 4 qui sera exécutée.

Et il est possible de mettre plusieurs elif :

if condition 1 :
    instruction 1
    instruction 2
elif condition 2 :
    instruction 3
elif condition 3 :
    instruction 4
    instruction 5
else :
    instruction 6 

Dans une pile comme celle-ci, les elif et le else sont relatifs au if qui les précèdes : leur action dépend du résultat de la première condition.

Exemple 1

n = 5
 
if n > 0 :
    print "n est positif"
elif n < 0 :
    print "n est négatif"
else :
    print "n est égal à zéro"

Résultat avec n = 5 :

n est positif

Le if était vrai donc son instruction a été exécutée et le reste à été sauté.

Résultat avec n = -5 :

n est négatif

Le if était faux et a été sauté mais le elif était vrai donc son instruction a été exécutée et le else a été sauté.

Résultat avec n = 0 :

n est égal à zéro

Le if et le elif étaient faux donc l'instruction du else a été exécutée.

Exemple 2

age = 20
 
if age > 0 :
    print "Le capitaine est né"
else :
    print "Le capitaine n'est pas encore né"
 
 
if age < 18 :
    print "Le capitaine est mineur"
else :
    print "Le capitaine est majeur"

Résultat avec age = 20 :

Le capitaine est né
Le capitaine est majeur

Résultat avec age = 0 :

Le capitaine n'est pas encore né
Le capitaine est mineur

Exemple 3

age = 20
 
if age > 0 :
    print "Le capitaine est né"
    if age < 18 :
        print "Le capitaine est mineur"
    else :
        "Le capitaine est majeur"
else :
    print "Le capitaine n'est pas encore né"

Résultat avec age = 20 :

Le capitaine est né
Le capitaine est majeur

Résultat avec age = 0 :

Le capitaine n'est pas encore né

Exemple Maya

import maya.cmds as mel
 
#créer une sphère et la nommer "boule" (objet et shape)
#la lier à un matériau blinn1
 
#récupère et affiche la position en x de l'objet boule
x = mel.getAttr('boule.tx')
print x
 
if x < 0:
    #si x < 0 on colore la boule en rouge
    mel.setAttr('blinn1.color', 1,0,0)
elif x > 0 :
    #si x > 0 on colore la boule en bleu
    mel.setAttr('blinn1.color',0,0,1)
else :
    #sinon (donc si x == 0) on colore la boule en vert
    mel.setAttr('blinn1.color',0,1,0)

Les boucles

Les boucles permettent de répéter un bloc d'instructions un certain nombre de fois.

La boucle while

La boucle while fonctionne ainsi:

Tant que condition : fais ceci

On l'écrit ainsi:

while condition :
    instructions

Comme pour les instructions conditionnelles, il faut mettre “:” après la condition et une tabulation avant les instructions.

La boucle while ne contiens pas automatiquement de condition de sortie, il est nécessaire de vérifier qu'elle s'arrêtera à un moment donné ou elle tournera à l'infini, obligeant par exemple à fermer Maya.

Nous devons donc créer une condition de sortie, au moyen d'une variable s'incrémentant (dont la valeur augmente) à chaque tour:

# on crée une variable qui nous servira de compteur
compteur = 0
while compteur < 10 : # tant que compteur < 10
    # affiche la valeur de compteur
    print compteur,
    # ajoute 1 a compteur
    compteur = compteur + 1
0 1 2 3 4 5 6 7 8 9

La variable compteur s'incrémente de 1 à chaque tour de la boucle, et au moment ou elle vaut 10 la condition étant fausse la boucle s'arrête.

Exemple dans Maya
import maya.cmds as mel
# on initialise le compteur a 0
c = 0 
while c < 15 : # tant que c est inférieur à 15
    # on crée un cube
    mel.polyCube()
    # et on le bouge en x et en z à la valeur de c
    mel.move(c,c,0)
    # on incrémente le compteur
    c = c + 1

La boucle for...in

La boucle for…in fonctionne (au plus simple), ainsi :

Pour toute valeur contenue dans cette plage de nombres : fais ceci

for valeur in range(debut,fin) :
    instructions
La boucle for n'inclue pas le dernier nombre de range : range (5,10) s'arrêtera à 9.

A noter que l'on peut mettre en fait tout conteneur que l'on veut à la place de range() (listes, tableaux…).

Exemples simples, avec range()
# pour chaque nombres de 257 à 260
for val in range(257,261) :
    print val, # affiche la valeur
257 258 259 260
# pour chaque nombres de 0 à 4
for val in range(0,5) :
    print val, # affiche la valeur
0 1 2 3 4

On aurait dans ce cas (affichage de x nombres depuis 0) pu écrire, de manière simplifiée:

# pour chaque nombres de 0 à 4
for val in range(5) :
    print val, # affiche la valeur
0 1 2 3 4
Exemples en chaines de caractères, listes et tableaux
tata = 'tomate'
# pour chaque élément de la chaine de caractères
for val in tata :
    print val, # on affiche la valeur
t o m a t e
# liste de tous les objets dont le nom contiens "tomate"
tata = ls('*tomate*')
# pour chaque élément de la liste
for val in tata :
    print val, # on affiche la valeur
objet_tomate objet_tomateMesh tomate_light
tata = 'tomate'
# pour chaque élément du tableau
for val in ['toto', 7, tata, 0.85] :
    print val, # affiche la valeur
toto 7 tomate 0.85
Python, contrairement à d'autres langages, permet de manipuler des tableaux contenant des types différents.

Quand utiliser l'une ou l'autre ?

La boucle while :

  • si vous avez à augmenter (ou réduire) le compteur d'un autre pas que 1
  • si la vitesse d'exécution est primordiale : elle est la plus rapide

La boucle for :

  • si vous incrémentez le compteur 1 par 1 :
    • si vous incrémentez le compteur d'une valeur à une autre, avec in range(min,max)
    • si vous voulez juste faire x fois une action, avec in range(x)
  • si vous voulez que le compteur prenne tour à tour les différentes valeurs d'un tableau, avec in [a,b,…]
  • … ou d'une liste, avec in (a,b,…)
  • … ou d'une chaine de caractères, avec in 'tomate'

Cas particulier : le break

L'instruction break permet d'arrêter une boucle. Associé à une condition dans la boucle il permet de spécifier des conditions de sorties particulières.

Exemple
for i in range(-10,11):
    j = 10.0/i
Error

Il y a une erreur car lorsque i deviens égal à 0, le calcul 10.0/i est impossible (divide by zero!). Pour éviter l'erreur, on peut donc utiliser l'instruction break :

for i in range(-10,11):
    if i == 0:
        break # arête la boucle si i = 0
    else:
        j = 10.0/i
    print i
-10 -9 -8 -7 -6 -5 -4 -3 -2 -1

Le code s'est bien exécuté jusqu'à ce que i prenne pour valeur 0, et une fois le break rencontré a stoppé la boucle.

Variante : le continue

L'instruction continue permet, dans une boucle, de sauter l'étape en cours.

Exemple
import maya.cmds as mel
for i in range(-10,11):
    if i == 0:
        continue # saute la valeur i = 0 et continue
    else:
        j = 10.0/i
    print i
-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 1 2 3 4 5 6 7 8 9 10

Le code s'est exécuté jusqu'à ce que i prenne pour valeur 0, et une fois le continue rencontré, est directement passé au tour de boucle suivant, sans passer par la case départ et sans toucher 1000 euros.

Le try...except

Le try…except permet d'essayer quelque chose et, si cela fait une erreur, faire autre chose:

essaie : ça
si ça fait une erreur : fait ça

try :
    instructions
except :
    instructions

Contrairement à une if associé à un continue, on n'a ici pas à se soucier à trouver l'étape qui amène l'erreur.

Exemple simple

for i in range(-2,3): # de -2 à 2
    try: #j’essaye de faire ce calcul
        x = 10/i
        print x
    except: # si il y a eu erreur, j’affiche ceci
        print "erreur sur", i
-2 
-1 
erreur sur 0
1 
2 

Exemple dans Maya

import maya.cmds as cmds
 
# liste les objets dont le nom comprend "Light"
lum = cmds.ls("*Light*")
print lum
for i in lum:
	try: # tester l'on peut regler l'intensite
		cmds.setAttr(i+".intensity")
	except: # sinon ce n'est pas une lumiere
		print i, " pas une lumiere"
pointLight1 areaLight1 lightView DefaultLightsList
lightView pas une lumiere
DefaultLightsList pas une lumiere

Les fonctions sont des blocs d'instructions auxquels l'on donne un nom, ce qui permet de les exécuter depuis n'importe quel endroit du programme. Tout ce qu'on utilise du type polyCube(), setAttr(), ls() sont des fonctions.

On crée une nouvelle fonction en utilisant le mot clé def (définir) suivi de son nom et de parenthèses…

def nomFonction() :
    instructions

…et on l'appelle simplement en criant son nom (“hé, jean-louis!”) :

nomFonction()

Comme toutes les instructions composées, ce qui fait parti de la fonction doit être indenté.

On peut par exemple faire une fonction créant un cube et le déplaçant…

def creerCube() :
    mel.polyCube()
    mel.move(10,0,0)

… et ainsi créer pleins de cubes positionnés à 10 sur x en écrivant :

creerCube()
creerCube()
...

Toutefois ainsi fait cela ne sert pas à grand chose. Ce serait plus utile de pouvoir dire à ma fonction la taille de mon cube par exemple, non?

Arguments de la fonction

Il est possible de faire passer une/des valeur à la fonction, et c'est là que tout l'intérêt réside :

Pour que ma fonction attende un argument, par exemple la hauteur de mon cube dans ma superbe fonction creerCube, on écrira :

def creerCube(hauteur) :

Ainsi dans ma fonction, la variable hauteur peut être utilisée…

def creerCube(hauteur) :
    mel.polyCube(height = hauteur)
    mel.move(10, 0, 0)

…et elle correspondra à ce que l'on aura demandé en appelant la fonction :

creerCube(hauteur = 10)
creerCube(hauteur = 50)

Pour définir plusieurs arguments séparez-les simplement par une virgule en créant la fonction. Par exemple rajoutons un argument position à notre fonction :

# création de la fonction
def creerCube(hauteur, position) :
    mel.polyCube(height = hauteur)
    mel.move(position, 0, 0)
 
# appel de la fonction
creerCube(hauteur = 10, position = 10)
creerCube(hauteur = 50, position = 5)

A noter que l'on n'est pas obligé d'indiquer le nom de l'argument lorsqu'on appelle la fonction :

creerCube(10,20)
creerCube(50,10)

Toutefois dans ce cas l'ordre des arguments (s'il y en a plusieurs) doit nécessairement être respecté.

Argument optionnel

On peut vouloir un argument sans qu'il soit obligatoire, comme par exemple… la position du cube de la fonction creerCube. On écrira alors :

def creerCube(hauteur, position = 10) :
    mel.polyCube(n='monCube',height=hauteur)
    mel.move(position,0,0)

Ainsi au cas ou l'argument position n'est pas fourni, la fonction lui donnera une valeur de 10 :

# crée un cube de hauteur 5, à la position par défaut
creerCube(hauteur = 5)
# crée un cube de hauteur 5, à la position 20
creerCube(hauteur = 5, position = 20) 
Les arguments optionnels doivent nécessairement être placés à la fin de la liste d'arguments de la fonction.

Arguments illimités

Il est aussi possible de définir qu'une fonction peut prendre n'importe quel nombre d'arguments. Pour cela, dans la définition de la fonction on écrira :

def fonction(&args) :
fonction(1,2,3,4) # args = (1,2,3,4)

Le & devant la variable indique que toutes les valeurs qui seront données lors de l'appel de la fonction devront être stockées dans une liste nommée ici args.

Il peut n'y avoir aucun argument : args serait simplement une liste vide.

Cet argument illimité peut être utilisé conjointement avec des arguments habituels…

def fonction(a, &args) :
fonction(1,2,3,4) # a = 1 et args = (2,3,4)

…et avec des arguments optionnels :

def fonction(a, b = 0, &args) :
fonction(1) # a = 1 et b = 0
fonction(1,2) # a = 1 et b = 2
fonction(1,2,3,4) # a = 1, b = 2 et args = (3,4)
Dans ce cas les arguments optionnels seront nécessairement renseignés avant qu'args ne prenne le relais.
Cet argument illimité doit nécessairement être placé à la fin de la liste d'arguments.

Docstring

Quand vous créez vos fonctions il est indispensables de les expliquer, les documenter. Une fonction est faite pour pouvoir être réutilisées plus tard, être utilisée par quelqu'un d'autre, être vendue au M.I.T., etc… Chercher l'utilité et le le fonctionnement de maFonctionNumero53 pendant des heures peut s'avérer frustrant.

Donc, pour la documenter on ajoute un petit commentaire au début expliquant à quoi elle sert, c'est ce que l'on appelle une docstring :

def creerCube(hauteur, position = 10) :
    """
    Crée un cube avec une hauteur spécifiée 
    et a une position en x spécifiée
    """
    mel.polyCube(n='monCube',height=hauteur)
    mel.move(position,0,0)

Ce commentaire doit être placé à cet endroit, entre triples guillements. Des programmes permettent ensuite de scanner un code source pour créer et mettre en page automatiquement une documentation de toutes ses fonctions, d'où le nom docstring (doc from string).

Python Docstring conventions.

Exemple concret dans Maya

Cette fonction crée une ligne de colonnes du nombre voulu, à la taille voulue, espacée d'une distance voulue:

import maya.cmds as mel
 
def ligneColonnes(n, hauteur, espacement) :
    """
    Crée n colonnes cotes à cotes,
    de hauteur et espacement spécifiés.
    """
    for i in(n) : # fais ceci n fois
        # crée un cube de hauteur donnée
        mel.polyCube(h = hauteur)
        # le déplace selon l'espacement donné 
        mel.move(i * espacement, 0, 0) 
 
# exécute la fonction
ligneColonnes(nombre = 10, hauteur = 5, espacement = 2)

Si vous avez des questions, des remarques, des suggestions, n'hésitez pas à m'en faire part.

~~DISCUSSION~~