Aide-mémoire : Lua pour développeurs Python

  Lua python

Table des matières

Aide-mémoire de syntaxe Lua lorsqu'on vient de Python : faux amis, petites différences etc

1. Généralités

Variables et types

Python Lua
x = 42 local x = 42
name = "Bob" local name = "Bob"
True, False true, false
None nil

Types et conversions

Python Lua
type(x) type(x)
str(x) tostring(x)
float(s) tonumber(s)
bool(x) pas d'équivalent direct

Opérateurs logiques

Python Lua
a == b a == b
a != b a ~= b
a and b a and b
a or b a or b
not a not a

Opérateurs arithmétiques

Python Lua
a**n a^n
a % b a % b

Conditions

Python Lua
if cond: if cond then
elif cond: elseif cond then
else: else
fin de bloc implicite end

Boucles

Attention la borne de fin est incluse dans Lua, contrairement aux range Python où elle est exclue. Il y a des avantages et des inconvénients.

Python Lua
while cond: while cond do
for i in range(10): for i = 0, 9 do
for i in range(1,11): for i = 1, 10 do
for i in range(10,0,-1): for i = 10, 1, -1 do
break break
pas de do ... while en Python repeat ... until cond
continue Inexistant.

Attention, il n'y a pas de continue en Lua. If faut soit encapstuler dans un if, ce qui fait augmenter l'indentation, soit au pire utiliser un goto comme ceci :

for i = 1, 10 do
    if condition then goto continue end
    --- suite de la boucle
    ::continue::
end

Fonctions

Python Lua
def f(x): local function f(x)
return x return x
lambda x: x**2 function(x) return x^2 end

Valeurs multiples

Python Lua
return a, b return a, b
a, b = func() local a, b = func()

Gestion d'erreurs

Python Lua
try: pcall(function() ... end)
raise Exception() error("message")
except Exception as e: récupération via pcall

Modules

Python Lua
import json local json = require("dkjson")
from x import y Si le module x retourne une table : local y = require("x").y

Classes / objets

Python Lua
self.method() self:method()
obj.method() obj.method() (sans passage implicite de self)

Faux amis importants

Python Lua
[] est faux {} est vrai
"" est faux "" est vrai
0 est faux 0 est vrai
variables locales par défaut variables globales sans local

En Lua, les seuls valeurs falsy sont nil et false. Tout le reste est évalué à true.


2. Listes et dictionnaires Python, tables Lua

Généralités

Python Lua
[] {}
[1,2,3] {1,2,3}
{} {}
{"a": 1} {a = 1} ou {["a"] = 1}
lst[0], lst[1] t[1], t[2]
dict["name"] t["name"] ou t.name
len(lst) #t
",".join(lst) table.concat(t, ",")

Attention : #t est imprévisible pour un tableau "sparse" ou qui n'est pas indexé par des entiers contigus.

Ajouter, supprimer, insérer

Python Lua
dict[k] = v t[k] = v
lst.append(x) table.insert(t, x) ou t[#t+1] = x
lst.extend(other) boucle ou Penlight tablex.insertvalues()
lst.insert(k-1, x) table.insert(t, k, x) (décale le reste)
del lst[k] t[k] = nil (décale le reste)
lst.pop() table.remove(t)
lst.pop(i) table.remove(t, i) (décale le reste)

Dans les deux derniers cas, la valeur supprimée est retournée, en Python comme en Lua.

Parcours

Python Lua
for x in lst: for _, x in ipairs(t) do
for i,x in enumerate(lst): for i, x in ipairs(t) do
for k,v in dict.items(): for k,v in pairs(t) do

Recherche

Python Lua
value in lst boucle manuelle
key in dict t[key] ~= nil

Exemple :

local function contains(t, value)
    for _, v in ipairs(t) do
        if v == value then
            return true
        end
    end
    return false
end

Compréhensions

NOPE

Copie

Il n'y a pas d'équivalent natif de copy.copy(x), copy.deepcopy(x) ou x.copy(). Il faut faire une boucle manuelle ou bien utiliser une librarie comme Penlight :

local tablex = require("pl.tablex")
local copy = tablex.deepcopy(tbl)

Tri

Python Lua
lst.sort() table.sort(t)
sorted(lst) copier puis table.sort()

Filter, map, reduce

Lua n'a pas nativement les équivalents de filter(fn, lst) , [x for x in lst if cond], map(fn, lst), list(map(...)).

Avec la librarie Penlight, on peut écrire :

local tablex = require("pl.tablex")
local result = tablex.map(fn, tbl)

3. Chaînes de caractères

Les chaînes sont immutables en Lua, et ne sont pas des tables contenant chaque caractère. Comme pour les tables, le premier caractère est celui ayant un index égal à 1, pas 0.

Généralités

Python Lua
"a" + "b" "a" .. "b"
len(s) #s
s[0] string.sub(s, 1, 1)
s[k-1] string.sub(s, k, k)
s[:3] string.sub(s, 1, 3)
s[3:] string.sub(s, 4)
s[-1] string.sub(s, -1)
s.lower() string.lower(s)
s.upper() string.upper(s)

Recherche

Python Lua
s.find("abc") string.find(s, "abc")
"abc" in s string.find(s, "abc") ~= nil
s.startswith(x) s:sub(1,#x) == x
s.endswith(x) s:sub(-#x) == x

Remplacement

Python Lua
s.replace(a,b) string.gsub(s,a,b)

Découpage

Il n'y a pas d'équivalent natif de s.split(",").

Avec la librairie Penlight :

local stringx = require("pl.stringx")

stringx.split(s, ",")
table.concat(lst, ",")

Formatage

Python Lua
f"{x}" string.format("%s", x)
f"{n:.2f}" string.format("%.2f", n)

Expressions régulières

Python Lua
re.search() patterns Lua
re.match() patterns Lua
regex complètes bibliothèque LPeg

4. Entrées / sorties et fichiers

Lecture complète

Python Lua
open(path).read() io.open(path):read("*a")

L'ouverture sécurisée with open(path) as f: n'a pas d'équivalent natif, à la place on peut faire :

local f = assert(io.open(path, "r"))
local data = f:read("*a")
f:close()

Lecture ligne par ligne

Python Lua
for line in open(path): for line in io.lines(path) do

Écriture

Python Lua
open(path,"w") io.open(path,"w")
f.write(text) f:write(text)

Append

Python Lua
open(path,"a") io.open(path,"a")

Exemple :

local f = assert(io.open("log.txt", "a"))
f:write(os.date("[%Y-%m-%d %H:%M:%S] "), "Message\n")
f:close()

Le mode "a" ne permet pas de lire, seulement d'écrire. Les modes d'ouverture sont :

  • "r" : lecture
  • "w" : écriture (efface le contenu existant)
  • "a" : ajout à la fin
  • "r+" : lecture/écriture sans effacer
  • "w+" : lecture/écriture en effaçant
  • "a+" : lecture/écriture avec ajout à la fin

Existence d'un fichier

Python Lua
os.path.exists(path) ouverture test
local f = io.open(path, "r")

if f then
    -- ??
    f:close()
else
    -- ???
end

Suppression, Renommage

Python Lua
os.remove(path) os.remove(path)
os.rename(a,b) os.rename(a,b)

Répertoire courant

Python Lua
os.getcwd() LuaFileSystem : lfs.currentdir()

Liste des fichiers

Python Lua
os.listdir(path) LuaFileSystem
local lfs = require("lfs")

for file in lfs.dir(path) do
    print(file)
end

JSON

Il faut importer une librairie gérant le json:

local json = require("dkjson")
-- ou : local json = require("cjson")

Ensuite, dans les deux cas :

local f = assert(io.open("data.json", "r"))
local t = json.decode(f:read("*a"))
f:close()

Attention, en cas d'erreur de décodage, cjson lève une exception alors que dkjson retourne une valeur d'erreur, que l'on peut gérer avec local t, pos, err = json.decode(f:read("*a")).

Pour lire un fichier JSONL :

for line in io.lines("data.jsonl") do
    local obj, pos, err = json.decode(line)

    if obj then
        print(obj.name)
    else
        print("Error :", err)
    end
end