Les instructions composées
Structure
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
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.
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
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
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
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)
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.
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)
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).
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~~