======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 [[operateurs|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===== 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//). [[http://www.python.org/dev/peps/pep-0257|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~~