J'ai récemment touché Clojure pour une raison quelconque.
Pour ceux qui utilisent des langages procéduraux tels que C et Python depuis près de huit ans, au début, il y avait une certaine confusion sur les «langages fonctionnels», mais d'un autre côté, Python incorpore de nombreux avantages des langages fonctionnels. J'ai aussi remarqué.
Par conséquent, je voudrais essayer combien de choses fonctionnelles de type langage peuvent être faites avec Python en me référant à l'exemple Clojure.
Cette fois, ayato-p a publié Idioms du "Guide japonais de Clojure". Implémentons le contenu de /clojure-beginner/idioms/index.html) en Python. La version de Python disponible est la 3.6.1.
[0 1 2 3 4]
[:a :b :c :d :e]
Puisqu'il n'y a pas de "mot-clé" en Python, une chaîne de caractères est utilisée à la place. C'est facile avec le zip.
a = [0, 1, 2, 3, 4]
b = [":a" ":b" ":c" ":d" ":e"]
zip(a, b)
# -> <zip at 0x111a14548>
Oups, Python 3 fait un usage intensif des itérateurs. Il ne sera pas évalué tel quel, donc si vous souhaitez voir chaque élément, vous devez le placer dans une liste.
list(zip(a, b))
# -> [(0, ':a'), (1, ':b'), (2, ':c'), (3, ':d'), (4, ':e')]
{:name "ayato-p"
:age "24"
:address "Japan"}
Concaténez les paires (clé, valeur) dans le dictionnaire à l'aide de la chaîne du module itertools. L'astérisque "*" est un opérateur pour passer des éléments de liste comme arguments de fonction.
import itertools
d = {":name": "ayato-p",
":age": "24",
":address": "Japan"}
list(itertools.chain(*d.items()))
# -> [':name', 'ayato-p', ':age', '24', ':address', 'Japan']
(def v ["foo" "bar" "baz"])
(defn f [& args]
(clojure.string/join ", " args))
La manière de transmettre les arguments est la même que celle que nous avons faite ci-dessus. Vous utilisez également un astérisque lors de la définition d'une fonction qui accepte des arguments de longueur variable.
v = ["foo", "bar", "baz"]
def f(*args):
return ", ".join(args)
f(*v)
# -> 'foo, bar, baz'
Lorsque vous passez un dictionnaire, utilisez deux astérisques.
m = {"name": "ayato-p", "age": 24}
def g(name, age):
return "name:" + name + ", age:" + str(age)
g(**m)
# -> 'name:ayato-p, age:24'
(def people [{:name "ayato_p" :age 11}
{:name "alea12" :age 10}
{:name "zer0_u"}])
(remove nil? (map :age people)) ;(11 10)
(keep :age people) ;(11 10)
Utilisez simplement la notation d'inclusion de liste avec l'expression conditionnelle.
people = [{":name": "ayato_p", ":age": 11},
{":name": "alea12", ":age": 10},
{":name": "zer0_u"}]
[x[":age"] for x in people if ":age" in x]
# -> [11, 10]
L'utilisation est une instance.
isinstance(True, bool) # -> True
isinstance(False, bool) # -> True
isinstance("", bool) # -> False
isinstance(None, bool) # -> False
isinstance(0, bool) # -> False
isinstance(1, bool) # -> False
C'est la même chose pour Clojure et Python.
None or "ayato-p"
# -> "ayato-p"
Cependant, tout ce qui devient False lorsqu'il est booléen (None, 0, False, liste vide, etc.) s'applique, donc je pense qu'il vaut mieux l'utiliser si sérieusement.
Vous pouvez mesurer la longueur avec len ou l'évaluer avec si telle qu'elle est. Si vous le mettez entre booléen, True / False sera retourné en fonction de la présence ou de l'absence du contenu.
ev = []
v = [1, 2]
if ev:
print("not empty")
else:
print("empty")
# -> empty
if v:
print("not empty")
else:
print("empty")
# -> not empty
bool(ev)
# -> False
bool(v)
# -> True
(def m {:foo 1 :bar 2})
(cond-> m
true (assoc :baz 3)) ;{:foo 1, :bar 2, :baz 3}
(cond-> m
false (assoc :baz 3)) ;{:foo 1, :bar 2}
en utilisant if et dict
m = {":foo": 1, ":bar": 2}
dict(m, **{":baz": 3}) if True else m
# -> {':bar': 2, ':baz': 3, ':foo': 1}
dict(m, **{":baz": 3}) if False else m
# -> {':bar': 2, ':foo': 1}
C'est la première fois que j'utilise la fonction dict de cette manière. Lors de l'écriture d'un programme en Python, je pense qu'il est plus courant de réécrire le contenu de dict avant de l'utiliser.
(reduce (fn [acc x]
(if (zero? x)
(reduced 0)
(* acc x)))
1
(cycle [9 8 7 6 5 4 3 2 1 0]))
Étant donné que réduit n'est pas en Python, nous utilisons des exceptions pour implémenter des fonctionnalités similaires.
import functools
class Reduced(Exception):
def __init__(self, data):
super().__init__()
self.data = data
def myreduce(f, it):
try:
return functools.reduce(f, it)
except Reduced as e:
return e.data
def mymultiply(acc, x):
if x == 0:
raise Reduced(0)
return acc * x
myreduce(mymultiply, [9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
# -> 0
Facile si vous utilisez la notation d'inclusion de dictionnaire.
m = {"key1": 1,
"key2": 2,
"key3": 3}
{":" + k: v for k, v in m.items()}
# -> {':key1': 1, ':key2': 2, ':key3': 3}
Si vous souhaitez modifier les données de la liste, vous pouvez utiliser pop. Vous pouvez également créer une nouvelle liste à l'aide de la notation d'énumération et d'inclusion de liste.
l = [9, 8, 7, 6, 5, 4, 3, 2, 1]
l.pop(5)
l
# -> [9, 8, 7, 6, 5, 3, 2, 1]
l = [9, 8, 7, 6, 5, 4, 3, 2, 1]
[x for i, x in enumerate(l) if i != 5]
# -> [9, 8, 7, 6, 5, 3, 2, 1]
Le Python ordinaire ne peut pas gérer les instances Java. Il semble y avoir un Python implémenté en Java appelé Jython, mais il semble que le développement stagne, alors sautez-le.
Il s'agit généralement d'une boucle for.
Ignorez-le car la source dit "Je ne le recommande pas beaucoup".
(filter identity [nil false true 1 "hello" [1 2] {:foo 1} :hoge])
;; (true 1 "hello" [1 2] {:foo 1} :hoge)
C'est aussi une notation d'inclusion de liste
[x for x in [None, False, True, 1, "hello", [1, 2], {":foo": 1}] if x]
# -> [True, 1, 'hello', [1, 2], {':foo': 1}]
Comme déjà mentionné ci-dessus, nous utiliserons enumerate.
list(enumerate(["a", "b", "c", "d", "e"]))
# -> [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]
En faisant cela, vous pouvez l'utiliser comme suit.
[str(i) + " is " + x for i, x in enumerate(["a", "b", "c", "d", "e"])]
# -> ['0 is a', '1 is b', '2 is c', '3 is d', '4 is e']
(defn find-first [pred coll]
(first (drop-while (complement pred) coll)))
Il semble que vous devriez écrire une boucle for bâclée, mais je ne l'écrirai pas! !! Créez un générateur et utilisez next pour récupérer le premier élément.
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
next(x for x in l if x > 4)
# -> 5
Exemple d'extraction du plus petit nombre premier supérieur à un certain nombre naturel par division d'essai
import itertools
def isprime(x):
return next((0 for n in range(2, int(x ** 0.5) + 1)
if x % n == 0), 1)
next(x for x in itertools.count(1000) if isprime(x))
# -> 1009
(Ajouté le 20 juillet 2017) Dans le premier jugement, il est plus concis d'utiliser "all" qui renvoie vrai lorsque tous les éléments d'itérable sont vrais.
def isprime(x):
return all(x % n for n in range(2, int(x ** 0.5) + 1))
Pouvez-vous nous donner une comparaison rapide entre Clojure et Python? Puisque je suis un débutant de Clojure, il peut y avoir beaucoup de choses que Clojure peut faire mais Python ne le peut pas.
Cependant, si vous le regardez comme ceci, vous pouvez voir qu'en Python, en utilisant la notation d'inclusion de liste et les expressions de générateur, il est possible d'écrire un traitement de type langage fonctionnel de manière très compacte sans écrire de noms de fonction supplémentaires.
Vous n'avez pas à vous forcer à utiliser le générateur comme dans le dernier exemple, mais si vous le regardez dans la mesure où vous pouvez faire quelque chose comme ça, cela peut vous aider à écrire du code un jour.
A bientôt ~.
Recommended Posts