======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~~