Mon aventure avec ChatGPT

A moins d'être benêt comme certains, l'utilisateur de ChatGPT comprend vite qu'il faut prendre le machin pour ce qu'il est, une machine qui génère du texte, et non pour ce que certains le vendent, une entité avec qui il serait possible de papoter. Seulement voilà : un machin qui génère du texte, c'est amusant, mais pour quoi en faire ? Et dans le cas présent, quoi en faire dans le domaine de la programmation ?
Question à son tour amusante, car dès lors, c'est un renversement de perspective qui s'opère. En effet, le produit d'Open AI n'apparaît pas comme un outil, que par définition il n'est intéressant d'utiliser qu'à condition de savoir à quoi il sert. A l'inverse, il apparaît comme un machin dont il est intéressant de chercher à faire un outil en l'utilisant pour trouver à quoi il sert. Le fait que le fonctionnement de ChatGPT soit si imprévisible qu'il est volontiers qualifié de boite noire vient rajouter du sel à l'exercice, car s'il a donc son petit caractère, on sent bien que cela ne va pas être simple de dompter le bestiau.
ChatGPT, l'I.A. qui a toujours raison
Bref, ChatGPT, on ne sait pas à quoi ça sert, et encore moins comment ça fonctionne, mais pour le développeur, c'est justement là que réside le fun. C'est que vu ainsi, utiliser ChatGPT permet de revivre une expérience similaire à celle de l'apprentissage de la programmation : on peut visiblement demander plein de choses amusantes à faire à la machine, et pour savoir ce qu'il est exactement possible en la matière, rien de mieux que de procéder d'emblée à des expérimentations ; par la suite, il sera toujours temps de tenter de rentrer dans les détails pour comprendre le pourquoi du comment, mais ce n'est pas un prérequis pour s'y mettre.
Partant, pourquoi ne pas chercher à l'utiliser pour créer un jeu ? Mon aventure avec ChatGPT relèvera donc un peu de la mise en abime : ce sera l'aventure de mon (jeu d')aventure avec ChatGPT, avant la dernière version qui repose sur GPT-4.
Continuer la lecture de "Mon aventure avec ChatGPT"
Mon aventure avec ChatGPT

Un traceroute roots en Python avec Scapy

Scapy est un package de Python bien connu dans le monde du hacking. Il permet d'interagir à bas niveau avec une interface réseau, c'est-à-dire de déterminer les octets qu'elle émet et de récupérer ceux qu'elle reçoit.
Scapy peut donc notamment être utilisé pour forger des trames et/ou paquets sur un réseau. Cela peut permettre de se livrer à des activités que la morale réprouve, comme l'ARP cache poisoning et autres joyeusetés. A l'inverse, comme nous le recommanderons, cela peut permettre de s'adonner à des activités tout à fait respectables, comme le diagnostic.
Scapy, pour sniffer, spoofer et autres
Dans tous les cas, se mettre à Scapy permet de se former au fonctionnement de réseaux en commençant par là où il faut commencer chaque fois qu'on prétend réellement apprendre quelque chose dans quel que domaine, c'est-à-dire à la base. C'est cette finalité pédagogique que poursuit cet article, à l'attention de tous ceux qui n'ont jamais mis le nez dans le réseau. Il présente comment réaliser une version simplifiée d'un outil qui figure inévitablement dans la boite à outils de tout hacker, à savoir traceroute.
Continuer la lecture de "Un traceroute roots en Python avec Scapy"
Un traceroute roots en Python avec Scapy

Les opérateurs étoile (* et **) en Python

En Python, chacun sait que l'opérateur * permet d'effectuer une multiplication sur des opérandes numériques, ou à répéter un opérande quelconque, tandis que l'opérateur ** permet d'effectuer une élévation à une puissance quelconque d'un opérande numérique :
print (2*3)
print (2*'Hello, world!')
print (2**3)
6
Hello, world!Hello, world!
8
Ce qui est moins connu, car elle est assez mal documentée, c'est la possibilité d'utiliser ces opérateurs pour du déballage (unpacking) d'itérables divers en vue de constituer un autre itérable. Par exemple :
x = ['A', 'B']
y = ('C', 'D')
z = [*x, *y]
print (z)
['A', 'B', 'C', 'D']
Comment est-il possible d'utiliser ces opérateurs de cette manière ? Et pour quoi faire ? L'exploration de la documentation de Python permet de constater qu'ils peuvent servir dans deux circonstances : pour créer des itérables, et pour fournir des arguments à une fonction. Explications...
Mise à jour du 19/05/2018 : Mention de notations supplémentaires pour créer un itérable à partir d'un autre.
Continuer la lecture de "Les opérateurs étoile (* et **) en Python"
Les opérateurs étoile (* et **) en Python

Syntaxes avancées (car ramassées) en Python

Il y a mille manières d'exprimer ce qu'on désire en langage naturel, et il en va de même avec un langage de programmation.
Certaines fomulations peuvent être clairement plus laconiques que d'autres, et d'aucuns considèrent que c'est démontrer sa maîtrise du langage que de les maîtriser. Toutefois, si jouer à ce petit jeu de la syntaxe ramassée permet d'économiser sur l'écriture, il ne permet certainement pas d'économiser sur la lecture, du moins tant que celui qui doit lire n'a pas appris à écrire pareillement.
Pour aider dans cet apprentissage, cet article évolutif se propose de recenser les syntaxes ramassées qu'un développeur peut rencontrer en lisant du code en Python (version 3.6.4), à condition qu'elles présentent une véritable utilité.
Pour l'heure, on trouvera des explications suivantes... :
L'article sera enrichi au fil des découvertes réalisées au fil de lectures. Ces mises à jour seront signalées.
Mise à jour du 27/04/2020 : Sur signalement de no_one, correction d'une coquille dans un usage fréquent du slicing.
Mise à jour du 09/04/2020 : Sur recommandation de Tchich, mention à l'utilisation de zip () pour extraire les colonnes d'un tableau.
Mise à jour du 08/03/2018 :
  • rappel de la typologie (et corrections !) ;
  • extraire une plage d'éléments d'une séquence (slicing).
Continuer la lecture de "Syntaxes avancées (car ramassées) en Python"
Syntaxes avancées (car ramassées) en Python

Paramètres et décorateurs de fonction en Python

Python permet d'écrire des fonctions comportant de nombreux paramètres qui peuvent avoir des mines des plus patibulaire, surtout si elles sont par ailleurs assorties de décorateurs. Par exemple :
def g (h):
	def k (prompt, *words, **complements):
		if complements['computer'] == 'Atari':
			complements['computer'] = 'Amiga'
		h (prompt, *words, **complements)
	return k
@g
def f (prompt, *words, **complements):
	for key, value in complements.items ():
		print (prompt + ':', ' '.join (words), value)
f ('HAL speaking', 'I', 'love', 'the', computer='Atari', drink='coffee')
HAL speaking: I love the Amiga
HAL speaking: I love the coffee
Il est important de ne pas se laisser abuser par cette apparente complexité. Maîtriser les différentes catégories de paramètres qu'il est possible d'utiliser est essentiel pour exploiter le potentiel de l'écriture de fonctions en Python au quotidien. Quant aux décorateurs, il est sans doute bien moins fréquent d'y avoir recours, mais comme ils peuvent se rencontrer, il est bon de savoir commment ils fonctionnent.
Continuer la lecture de "Paramètres et décorateurs de fonction en Python"
Paramètres et décorateurs de fonction en Python

Comment marche réellement la fonction super () de Python

La méthode super () de Python a inspiré un bon nombre d'explications. Toutefois, il apparaît qu'aussi sophistiquées qu'elles soient, elles sont toutes désespérément superficielles.
Je ne parle pas de celles qui le sont d'évidence, comme cette vidéo. L'auteur est bien gentil, mais sa présentation de super() se limite à assimiler la fonction à un moyen de déléguer un appel à la méthode __init__ () (par ailleurs, tout à fait improprement assimilée à un constructeur, comme si __new__ () n'existait pas...) surchargée dans une classe C à sa version dans une classe parent A. Autrement dit, à appeler A.__init__ () depuis C.__init__ (). Mais dans l'exemple, C hérite non seulement de A, mais aussi de B. Dès lors, les questions des commentateurs fusent : pourquoi B.__init__ () n'est-elle pas appelée ? Sincèrement, avant de publier une explication sur un sujet technique, son auteur devrait s'assurer qu'il maîtrise son sujet. Comme il le dit, "The super keyword is a little bit confusing in Python. It's been confusing for decades now and it's going to continue to be confusing as we move into the future. It's just something that's confusing". Tu m'étonnes! surtout après avoir entendu sa prétendue explication...
Non. Je parle d'explications d'auteurs qui ont pignon sur rue, comme Python's super() considered super! de Raymond Hettinger, à laquelle renvoie la documentation de super(), ou encore celle d'Alex Martelli, Anna Ravenscroft et Steve Holden dans leur Python in a Nutshell. Le moins qu'on puisse dire, c'est qu'on ne ressort pas illuminé de ces lectures. Sans doute, on comprend que super() permet de jouer avec le Method Resolution Order (MRO), mais quant à savoir exactement comment, c'est une autre affaire. Tout le monde se contente de terminer en recommandant d'utiliser systématiquement super() à tous les niveaux la hiérarchie des appels, et pour le reste renvoie sur l'algorithme C3, présenté comme abscons.
Bref, tout comme peu de personnes semblent avoir compris que JavaScript est un langage orienté objet à base de prototypes (et non de classes !), y'en a-t-il seulement qui ont compris comment la fonction super() de Python fonctionne vraiment ? Sérieusement, il y a de quoi nourrir de sérieuses inquiétudes quant au niveau d'exigence des développeurs désormais. Plus personne ne se donne la peine d'aller au fond des choses, ou quoi ?
On va donc arrêter de plaisanter, et expliquer sérieusement...
Continuer la lecture de "Comment marche réellement la fonction super () de Python"
Comment marche réellement la fonction super () de Python