Site original : Sam & Max: Python, Django, Git et du cul
Le protocole WebSocket vise à développer un canal de communication full-duplex sur un socket TCP.
LOL. C’est clair non ?
Vous inquiétez pas, tonton Sam est là.
Le Web a évolué. On est passé de Gopher a HTTP 1 puis 1.1. Et on a eu AJAX pour rafraîchir la page sans tout recharger.
Et maintenant on a des apps complètes qui font des centaines de requêtes au serveur alors même que l’utilisateur ne change pas de page. D’ailleurs, je parie que plein de gens ne savent même plus ce qu’est une page…
Le problème c’est qu’AJAX, c’est toujours HTTP, et HTTP est sans état (stateless) : il ne garde aucune information en mémoire d’une requête à l’autre. Ça a des avantages, mais cela implique qu’à chaque requête, il faut ouvrir une connexion et la refermer. Ce qui bouffe quelques ms à chaque fois, et d’autant plus si on utilise SSL.
Une autre limite, c’est que le serveur ne peut pas envoyer de données au client (ici le navigateur) si le client ne fait pas une requête au préalable. Du coup, pour savoir si il y a quelque chose de nouveau, le navigateur doit régulièrement faire des requêtes au serveur ou utiliser des gros hacks comme le long polling.
Les websockets (c’est un abus de langage, on devrait parler du protocole Websocket) ont été créés pour répondre à ces besoins : elles permettent d’ouvrir une connexion permanente entre le navigateur et le serveur. Ainsi, chaque requête est plus rapide, et plus légère. En prime, le serveur peut envoyer des requêtes au navigateur pour le prévenir qu’il y a du nouveau.
Ceci permet de faire tout ce que permettait de faire AJAX mais en plus rapide, et en plus léger. Et également d’envoyer des notifications (ce contenu a changé, un message est arrivé, l’autre joueur a fait cette action…) au navigateur au moment où l’événement se produit.
En gros, de faire des apps Web quasi temps réel.
Il existe d’autre technos pour faire cela : applets Java, flash, comet, server sent events…
Mais aucune n’ont décollé. Websocket est donc aujourd’hui la solution de facto.
Le protocole Websocket utilise l’abréviation ws
et wss
si SSL, les URLs vers des endpoints websocket ressemblent donc à : ws://domaine.tld/chemin/vers/truc/
.
Intelligemment, il utilise un handshake compatible avec celui de HTTP, permettant à un serveur de gérer les deux sur les mêmes ports. Donc on peut faire du Websocket sur le port 80 et 443. Néanmoins, certains proxy se gourent quand ils voient du websocket non chiffré et gauffrent votre connexion en la traitant comme du HTTP. Donc si vous voulez une app solide, investissez dans un certif SSL.
Tout ça fonctionne à partir de IE10. Notez comme IE est devenu le standard de ce qui ce fait de moins bien à tel point que je n’ai même pas besoin de vous parler des autres, vous savez que ça marche. Il existe en plus des plugins flash pour simuler des websockets sur les navigateurs anciens, c’est à dire les encore plus vieux IE.
Par défaut, les websockets permettent de faire de requêtes crossdomain, contrairement à AJAX. Avec les nouvelles apps qui utilisent NodeJS en local (comme popcorntime) on peut imaginer une nouvelle type d’attaque : une page web qui se connecte à un serveur websocket local de votre machine. Comme les websockets sont souvent utilisées pour du RPC, il y a du potentiel.
Vous noterez que ce qui prend du temps dans l’exemple c’est la connexion, qu’on ne fait qu’une fois. Ensuite l’échange de données est super rapide.
Ceci est un exemple Javascript, mais un client websocket n’est pas forcément un navigateur. En fait, c’est très précisément le cas avec WAMP, dont les clients peuvent être des programmes Python, Objective C, Java, C++, etc. L’avantage de WAMP, c’est qu’il automatise toute la machinerie pour découper la logique de son programme en divers fonctions et services, plutôt que d’avoir à tout faire à la main avec send()
et onmessage()
.
Dans tous les cas, il vous faudra un serveur qui supporte les Websockets pour l’utiliser. En Python, c’est Tornado ou Twisted (sur lequel est basé le serveur WAMP crossbar). En Javascript, c’est NodeJS. Quoi qu’il en soit, il vous faut un logiciel qui gère l’IO de manière non bloquante, car il y a de nombreuses connexions ouvertes en simultanées, si on veut que ça soit performant.
Il y a 4 gros freins à l’adoption de WAMP :
Toute les libs qui introduisent une nouvelle façon de travailler rencontrent ce problème. Quand les ORM sont sortis, c’était pareil. Quand les Django et Rails, et Symfony sont sortis, c’était pareil.
Mais puisqu’on le sait, on peut agir.
Les 3 premiers points ont déjà un début de solution, ce qui nous intéresse c’est donc le 4ème point.
Il y a de nombreuses choses à faire pour l’intégration : authentification, actions bloquantes, communications…
On ne peut pas tout résoudre d’un coup, mais une solution qui ratisse large serait de créer un bridge HTTP/WAMP.
Le principe : faire un client WAMP qui soit aussi client HTTP avec une API REST.
En envoyant des requêtes HTTP avec un webtoken pour s’authentifier, on peut faire un register/subscribe/call/publish sur le bridge en spécifiant une URL de callback. Le bridge transmet tout ça à routeur WAMP. Quand un événement arrive sur le bridge qui concerne une des URLs de callback, il fait une requête sur l’URL avec les infos arrivées via WAMP.
API :
POST /register/
{ // token d'authentification token: "fdjsklfqsdjm", // On enregistre des urls de callbacks pour chaque "function" exposées en RPC // Quand le bridge reçoit un appel RPC via WAMP, il fera une requête POST // sur la bonne URL. Votre app récupère les données via POST, et retourne // du JSON que le bridge va transmettre via WAMP. endpoints: { "nom_fonction_1": "http://localhost:8080/wamp/rpc/nom_fonction_1/", "nom_fonction_2": "http://localhost:8080/wamp/rpc/nom_fonction_2/" } } |
POST /subscribe/
{ token: "fdjsklfqsdjm", // On enregistre des urls de callbacks chaque abonnement à un topic. // Quand le bridge reçoit un message PUB via WAMP, il fera une requête POST // sur la bonne URL. Votre app récupère les données via POST. endpoints: { "nom_fonction_1": "http://localhost:8080/wamp/pub/nom_fonction_1/", "nom_fonction_2": "http://localhost:8080/wamp/pub/nom_fonction_2/" } } |
POST /call/nom_fonction/
{ token: "fdjsklfqsdjm", // Le bridge fera l'appel RPC, récupère la valeur de retour, et la renvoie // à cette URL via POST ou une erreur 500 en cas d'exception. callback: "http://localhost:8080/wamp/callback/nom_fonction", // Les params à passer à l'appel RPC params: ['param1', 'param2'] } |
POST /publish/nom_sujet/
{ token: "fdjsklfqsdjm", // Le bridge fera la publication WAMP // Les params à passer lors de la publication params: ['param1', 'param2'] } |
On peut rajouter des fioritures : recharger le fichier de config qui contient les API keys, se désabonner, désinscrire un callback RPC, etc.
Bien entendu, du fait d’avoir un intermédiaire, c’est peu performant, mais suffisant pour permettre une communication entre des apps existantes et vos apps WAMP et mettre un pied dedans.
Ceci permet une intégration générique, de telle sorte que tout le monde puisse intégrer son app facilement avec quelques requêtes HTTP. Néanmoins, avoir un plugin pour son framework plug and play faciliterait la vie de beaucoup de gens.
Donc la partie 2, c’est de faire des apps pour les frameworks les plus courants qui wrappent tout ça.
Par exemple, pour Django, ça permettrait de faire :
settings.py
WAMP_BRIDGE_URL = "http://localhost:8181/" |
urls.py
from wamp_bridge.adapters.django import dispatcher urlpatterns += ('', url('/wamp/, dispatcher), ... ) |
views.py
from wamp_bridge.adapters.django import publish, call, rpc, sub @rpc() def nom_fonction_1(val1, val2): # faire un truc @sub() def nom_topic_1(val1, val2): # faire un truc def vue_normale(request): publish('sujet', ['arg1']) resultat = call('function', ['arg1']) |
Ca répond pas à des questions du genre : “comment je fais pour garder mon authentification Django” mais c’est déjà super glucose.
On peut créer un bridge dans plein de langages, mais je pense que Python est le plus adapté.
Les clients JS utiliseraientt de toute façon nodeJS, qui n’a pas besoin de bridge, puisque déjà asynchrone. Un routeur en C demanderait de la compilation. PHP est trop moche. Java, c’est tout un bordel à setuper à chaque fois. C#, si il faut se taper Mono sous Linux…
En prime, le routeur crossbar est déjà en Python, donc a déjà tout sous la main pour le faire. On peut même penser à l’intégrer à crossbar plus tard histoire que ce soit batteries included.
Il faut une implémentation Python 2 et Python 3, donc une avec Twisted, et une avec asyncio.
Pour le client twisted, on peut fusionner le client WAMP ordinaire avec treq.
Pour asyncio, il y a aiohttp qui fait client et serveur.
On met les clés API dans un fichier de conf ou une variable d’env, une auth via token, et yala.
C’est le genre de projet intéressant car pas trop gros, mais suffisamment complexe pour être un challenge surtout qu’il faudra des tests unitaires partout, de la doc, bref un truc propre.
Je laisse les specs là, des fois qu’il y ait quelqu’un qui ait des envies de code cet hiver et cherche un projet open source dans lequel se lancer.
Si on se sent un peut foufou, on peut même transformer ça en bridget HTTP <=> anything, avec des backends pour ce qu’on veut : IRC, XMPP, Redis, Trigger Happy…
Ceci est un post invité de foxmask posté sous licence creative common 3.0 unported.
“C’est l’histoire d’un mec qu’est su’l’pont de l’Alma et regarde dans” … le python, et comme il débute, se demande mais putain de bordel, des projets à la con à pondre pour se lancer à l’assaut d’un langage, c’est toujours les mêmes trucs chiants que plus personne n’a envie de voir tels : forum, blog, wiki, cms. Alors comment être novateur un poil plus que ces projets sans (plus aucun) défit technique ?
A cette question je me suis dit, pourquoi ne pas produire “simplement” (toute proportion gardée) un équivalent libre au célébrissime IFTTT ?
IFTTT est un service qui vous permet de brancher entre eux, les services internet où vous possédez un compte, comme Twitter, Facebook pour ne citer qu’eux (parce que la liste est longue comme un python au moins;) Et donc quand un évènement défini se produit sur votre compte twitter, genre un tweet de votre poto tombe, le service réagit au quart de tour pour rebalancer les données ailleurs, sur Facebook, un blog et n’importe quoi qui vous chante.
Hé bien cet équivalent libre est Trigger Happy, et ce “principe” décrit ci-dessus défini un ESB (Entreprise Service Bus, très connu du monde Java), un BUS qui récupère des données de droite et vous les expédie à gauche.
Wikipedia le défini ainsi :
L’enterprise service bus (ESB) est une technique informatique intergicielle. Son but est avant tout de permettre la communication des applications qui n’ont pas été conçues pour fonctionner ensemble
3 aspects :
Dans la version simplifiée ceci donne :
Dans la version complète ceci donne :
On a au milieu un “tube” (pipeline) qui va permettre, via des “command” & settings & url & service provider, d’identifier les services “django th 1, 2, 3, 4″.
A un moment donné, à l’entrée du tube, arrive un “flux” de donnés identifié pour admettons “django th 1″ aka un flux RSS (au pif) puis on identifie une destination, admettons “django th 2″ aka “twitter”, et les données collectées repartent donc du tube vers twitter, comme le service s’attend à les recevoir.
Ça se passe bien mon zami : je m’en va (la fote est volontaire tout comme l’reste;) vous montrer la création d’un trigger, permettant d’extraire les billets du flux de mon blog et de les renvoyer sur Twitter en 5 étapes :
Ici en premier lieu vous pouvez voir la liste des services que Trigger Happy gere pour l’utilisateur courant (mézigues)
Puis l’accueil de l’appli où on remarquera que je suis radin en nombre de trigger affichés par page parce que … je me sers de l’appli via un browser sur mon smartphone m’sieur ‘dames :
Etape 1:
Etape 2:
Etape 3:
Etape 4:
Ensuite le moment venu, se déclenche ce trigger, et pour en voir le résultat, on peut consulter le billet que j’avais préparé le mois dernier pour une présentation Django Paris. Et qui au moment de la publication du billet, à 19h15 pétantes, est tombé sur twitter directement et Evernote dans la foulée.
Voilà !
Le défit est parti et n’attend plus qu’à ce que le nombre de services croissent. Pour cela rien de plus simple, j’ai fait une doc expliquant comment pondre un module django qui exploite le service de votre choix tel Buffer, Trello, Dropbox et j’en passe et des meilleurs. Tout ce dont on a besoin : l’API du service visé en python, créer un compte pour avoir accès au service et suivre le howto sur readthedoc
Last but not least aux dev : ca tourne avec django 1.7 / Python 2.7 et 3.4
Dernier détail: comme je suis sûr que vous vous demandez pourquoi ce nom de projet ? C’est un perso de la franchise Skylander auquel joue mon fils et comme le projet “trigger” à tirelarigot sur l’net, ca collait pile poil :)
Au début, on se demande comment parler à l’autre. Et comment on fait pour toucher ? Embrasser ? Baiser ? Obtenir une fellation ? Une sodomie ? Amener un scénario, un jeu SM ?
Et puis on grandit et on passe de l’autre côté de la barrière, et à chaque fois on se dit que c’était pas si mystérieux que ça au final.
Mais il reste toujours des situations inconnues, qui apparaissent obscures : par exemple, comment on arrive à un threesome, bordel ?
Comme d’habitude, je n’ai pas de recette magique, mais je peux vous donner quelques exemples de situations.
Marc, Marie et Mathilde ont orienté le rétroprojecteur vers le plafond pour regarder un film comme des loques, allongés sur deux canapés poussés l’un contre l’autre. Marc et Marie sortent ensemble, Marc et Mathilde ont fleurté. Tous les 3 sont sexuellement décontractés et ont déjà parlé de cul à table. Ils se connaissent, ils ont plusieurs soirées derrière eux.
En plein film, Marc caresse le bras de Marie, puis descend lentement vers sa chatte, sans y penser. Il finit par la caresser discrètement, et emporté, lui cale un doigt. Marie reste calme, mais Mathilde s’en aperçoit. Elle soulève le shirt de Marie, et commence à lui toucher un sein, puis à le prendre dans sa bouche. Tout en regardant le film, Marc et Mathilde s’occupent de Marie. Puis l’excitation monte, et Marc retire le pantalon de Marie pour lui faire un cuni…
Que s’est-t-il passé ?
Les 3 personnes se connaissaient. Elles sont à l’aise sexuellement. Elles ont déjà parlé de sexe.
En effet, on ne peut pas faire ça avec tout le monde : seul un certain type de personnes se retrouvent dans ces threesomes, les gens à l’aise avec le cul. Si vous avez du mal à assumer votre sexualité, si pour vous la fellation est un événement rare, ne tentez pas le plan à 3 tout de suite. Courir avant de marcher, tout ça…
Ensuite, ils savent qui ils sont : ils se sont vu plusieurs fois, ont parlé de sexe, se sont évalués. La prise de risque est allégée.
Ils sont seuls, dans une situation confortable, intime, et tout escalade doucement, naturellement. Personne n’a essayé de lancer un plan à 3. Ça s’est fait, non pas parce que chaque pas à amené vers, mais parce qu’aucun pas n’a été bloqué.
Car quand il s’agit de sexe, si une envie n’est pas satisfaite, c’est toujours imposé par une forme ou une autre de blocage. Il ne s’agit donc pas de pousser, mais d’être dans un contexte fluide, sans blocage.
La putain, est aussi la porte d’entrée aux plan à 3. Julien et Jérémy vont dans un bordel, embauchent une professionnelle en lui demandant si ils peuvent être deux pendant la séance. Ils se rejoignent dans la chambre, surmontent leurs inhibitions et se déshabillent. Au début ils hésitent, mais la prostituée connaît son métier et commence par en sucer un, exposant sa croupe à l’autre. Invité, le second la pénètre après avoir mis un préservatif. Les deux amis ne se toucheront pas, nullement intéressés l’un par l’autre, mais trouveront agréable l’expérience de partager une même femme.
Encore une fois, on note que tout le monde ne peut pas se retrouver dans cette situation : il faut des gens à l’aise avec l’idée de prostitution, et qui acceptent de se dévoiler, plus nus que jamais, l’un à l’autre dans une activité sexuelle.
Ce sont des amis, ils se connaissent. On en revient donc à la notion de confort et de confiance.
De son côté, la femme, accepte de prendre deux hommes en même temps, ce qui n’est pas forcément toujours le cas. Croire que les putes acceptent tout et que la permission est optionnelle est l’erreur des gens qui confondent sexe payé et esclavage. Une prostituée est une femme ordinaire, qui mérite le même respect.
Ingrid, Isabelle et Ignace ont tous beaucoup bu. Ignace a été gogo danseur par le passé et a fait sérieusement monté la température sur scène, mais maintenant ils se détendent, assis sur le même canapé. Ils ne parlent pas, ils sont dans la torpeur que le mélange de musique forte, d’éthanol et d’activité physique finit toujours par produire.
Ignace a lancé cette soirée chez lui, comme de nombreuses autres. Tout le monde le connaît comme quelqu’un de sociable, connaissant beaucoup de gens. Car il aime ça, il aime parler à autrui. Il aime aider. Il aime recevoir. Et toutes les personnes ce soir le savent.
Pour ne rien gâcher, Ignace est beau gosse, officiellement bi, et parle de sexe ouvertement. Il sera donc le pivot.
Dans le flou flottant de cet instant, les deux filles se reposent sur Ignace qui en embrasse une sur la tête. Il met ses bras autour d’elles. Ils restent ainsi un moment qui peut paraître long (mais difficile à évaluer car on perd la notion du temps dans ces conditions), affectueusement. Les mains d’Ignace caressent légèrement Ingrid et Isabelle. L’une l’embrasse sur la joue. L’autre l’embrasse sur la main. Il peut se passer un temps important entre deux baisers. Mais il décroit, jusqu’à ce que leurs corps remuent un peu, légèrement, l’un contre l’autre. Alors ils s’en vont dans la chambre.
Une fois de plus : les personnes sont connues, le milieu est sûr, il y a du confort et de la confiance, et bien entendu une aisance avec le sexe. L’alcool et le bruit catalysent cela, donnant une impression de proximité, voir d’intimité.
Ce ne sont pas les seules possibilités. Je pourrais parler de la drogue, des clubs échangistes, des plans à 3 planifiés avec son/sa partenaire…
Mais l’idée reste là :
Ceci s’applique même pour l’exemple avec la prostituée. Si vous ne le voyez pas, c’est que vous avez encore un blocage quelque part. Le premier blocage à faire sauter, c’est le vôtre.
Une autre chose importante là-dedans, c’est qu’aucun des acteurs n’a la peur d’être rejeté. Non pas qu’ils ont la certitude que ça va marcher, mais plutôt :
Autre chose : personne n’a rien demandé. Ils font. Pour ce genre de choses, il est plus facile de demander pardon que la permission.
Ce terme apparaît dans de nombreux articles du blog, et je prends parfois le temps de l’expliquer superficiellement. Évidemment, à de nombreux moments j’ai fait des tutos en ayant la connaissance de l’unpacking comme prérequis, et rien vers quoi faire un lien. Corrigeons ça, en attendant que je traduise les slides sur WAMP.
Normalement, si vous voulez mettre le contenu d’un tuple dans des variables, vous devez procéder ainsi :
>>> ducks = ('riri', 'fifi', 'loulou') >>> duck1 = ducks[0] >>> duck2 = ducks[1] >>> duck3 = ducks[2] >>> print(duck1) 'riri' >>> print(duck2) 'fifi' >>> print(duck3) 'loulou' |
L’unpacking, qu’on pourrait traduire par le terme fort moche de “déballage”, dans le sens “ouvrir un colis”, permet de faire la même chose, bien plus facilement :
>>> duck1, duck2, duck3 = ducks >>> print(duck1) 'riri' >>> print(duck2) 'fifi' >>> print(duck3) 'loulou' |
Il n’y a rien à faire, c’est automatique. La seule condition est que le nombre de variables à gauche du signe égal soit le même que le nombre d’éléments dans la collection de droite.
D’ailleurs, ça marche même avec un seul élément :
>>> ducks = ('riri',) >>> duck1, = ducks # notez la virgule >>> duck1 'riri' |
Et ça marche avec n’importe quel itérable, pas uniquement les tuples. Avec une liste, une string, un générateur…
>>> a, b, c, d = [1, 2, 3, 4] >>> c 3 >>> a, b = "12" >>> b '2' >>> def yolo(): yield "leroy" yield "jenkins" ... >>> nom, prenom = yolo() >>> nom 'leroy' >>> prenom 'jenkins' |
Ça marche bien entendu avec un dico ou un set, mais comme ils ne sont pas ordonnés, c’est pas très utile.
On peut utiliser l’unpacking dans des endroits inattendus. Par exemple, pour échanger la valeur de deux variables :
>>> a = 1 >>> b = 2 >>> a, b = (b, a) >>> a 2 >>> a, b = b, a # les parenthèses sont facultatives dans les tuples >>> b 2 |
Puisqu’on est dans les tuples sans parenthèses, on peut retourner un tuple et donner l’illusion de retourner plusieurs variables :
>>> def duckmebaby(): ... return "rifi", 'filou', 'louri' ... >>> et, hop, la = duckmebaby() >>> et 'rifi' >>> hop 'filou' >>> la 'louri' |
Allons plus loin.
On peut utiliser l’unpacking à l’intérieur d’une boucle for
. Souvenez vous que les itérables peuvent contenir d’autres itérables. Par exemple, j’ai une liste qui contient 3 tuples, chaque tuple contient deux éléments :
>>> scores = [('Monique', '3'), ('David', 10), ('Dick', 1)] >>> for score in scores: ... print(score) ... ('Monique', '3') ('David', 10) ('Dick', 1) |
Si je veux afficher le nom et le score l’un en dessous de l’autre :
>>> for nom_et_score in scores: ... print(nom_et_score[0]) ... print(nom_et_score[1]) ... Monique 3 David 10 Dick 1 |
Je peux appliquer l’unpacking dans la boucle pour rendre cette opération plus élégante :
>>> for nom, score in scores: ... print(nom) ... print(score) ... Monique 3 David 10 Dick 1 |
Cela marche avec des itérables plus gros, bien entendu. C’est aussi particulièrement utile avec des dictionnaires car on peut les transformer en itérable de tuples :
>>> scores = {'Monique': '3', 'David': 10, 'Dick': 1} >>> scores['Monique'] '3' >>> scores.items() # transformation ! dict_items([('Monique', '3'), ('David', 10), ('Dick', 1)]) >>> for nom, score in scores.items(): ... print(nom) ... print(score) ... Monique 3 David 10 Dick 1 |
Tout aussi utile, mais plus compliqué, est l’usage de l’unpacking dans l’appel de fonction. Pour cela, on utilise l’opérateur splat, l’étoile en Python.
Soit une fonction qui additionne des nombres :
>> def add(a, b, c): ... return a + b + c ... >>> add(1, 2, 3) 6 |
Oui, imaginons que je suis complètement débile, et que j’ai cette fonction pérave dans mon code. Vous noterez dans les articles que je l’utilise souvent sur le blog. C’est la fonction fourre tout pour expliquer un truc quand j’ai pas d’idée.
Maintenant, imaginez que je veuille additionner des canards. Si, ça marche en Python :
>>> 'riri' + 'fifi' + 'loulou' # what the duck ? 'rirififiloulou' |
Maintenant je me refais mon tuples de canards :
>>> # nous entrerons dans la bande à picsou, youhou >>> duckyou = ('riri', 'fifi', 'loulou') |
Si je veux utiliser ma fonction pourrie pour mon use case stupide, je ferai ceci :
>>> add(duckyou[0], duckyou[1], duckyou[2]) 'rirififiloulou' |
Voilà une perte de productivité intolérable, c’est pas comme ça qu’on va faire fructifier son sou fétiche.
On peut forcer l’unpacking avec l’étoile :
>>> add(*duckyou) 'rirififiloulou' |
Si on oublie l’étoile, le premier paramètre reçoit tout le tuple, et les autres paramètres rien :
>>> add(duckyou) Traceback (most recent call last): File "", line 1, in add(1) TypeError: add() missing 2 required positional arguments: 'b' and 'c' |
Les fonctions ont même le droit à un bonus car on peut unpacker des dictionnaires en utilisant la double étoile. Ca ne marche qu’avec les fonctions, et ça va déballer le dico pour que chaque paire clé/valeur soit passée comme nom et valeur de l’argument :
>>> def pas_add(arg1, arg2): print(arg1) print(arg2) ... >>> pas_add(arg1="Je suis la valeur 1", arg2="Je m'en branle de qui tu es") Je suis la valeur 1 Je m'en branle de qui tu es >>> dicocorico = {'arg1': 'cotcot', 'arg2': 'ouai je pête un cable, l\'avion me soule'} >>> pas_add(**dicocorico) cotcot ouai je pête un cable, l'avion me soule |
Quand on unpacke des paramètres, il faut s’assurer que le nombre d’arguments passé n’est pas supérieur à ceux existant, sinon ça plante :
>>> dicocorico = {'arg1': 'cocot', 'arg2': 'ouai je pête un cable, l\'avion me soule', 'dang': 'je suis en trop et ça fait chier tout le monde'} >>> pas_add(**dicocorico) Traceback (most recent call last): File "", line 1, in pas_add(**dicocorico) TypeError: pas_add() got an unexpected keyword argument 'dang' >>> stuplet = (1, 2, 3) >>> pas_add(*stuplet) Traceback (most recent call last): File "", line 1, in pas_add(*stuplet) TypeError: pas_add() takes 2 positional arguments but 3 were given |
Par contre, rien ne vous empêche de fournir moins d’arguments et de remplir les autres à la main :
>>> def encore_add(a, b, c, d): return a + b + 0 + c + d # je feinte ... >>> encore_add(10, *stuplet) 16 |
Et on peut bien entendu faire le mega mix. Par exemple, prenons la fonction print
, dont la signature accepte une infinité d’arguments positionnels et quelques arguments nommés :
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Aller, on va lui unpacker sa mère :
>>> ducks = ['riri', 'fifi', 'loulou'] # is this duck typing ? >>> keywords = {'sep': ' / ', "end": " : vous êtes du coin ? \n"} >>> print('picsou', *ducks, **keywords) picsou / riri / fifi / loulou : vous êtes du coin ? |
Ça c’est fait.
En Python 3, l’unpacking a été amélioré, et on peut maintenant faire de l’unpacking partiel :
>>> # exemple 100% repompé d'un autre article du blog. Duck it. >>> l = list(range(5)) >>> l [0, 1, 2, 3, 4] >>> a, *b = l >>> a 0 >>> b [1, 2, 3, 4] >>> a, *b, c = l >>> a 0 >>> b [1, 2, 3] >>> c 4 |
Ce qui peut être très pratique sur les longs itérables. Comment obtenir la dernière ligne d’un fichier ?
>>> *contenu, dernire_ligne = open('/etc/fstab') >>> dernire_ligne 'UUID=0e8c3132-8fa2-46d5-a541-2890db9b371f none swap sw 0 0\n' |
Ou alors, dans une boucle :
>>> for initiale, *reste in ducks: print(initiale) ... r f l |