J'ai essayé un langage fonctionnel avec Python

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.

Regrouper les éléments de plusieurs collections par index

[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')]

Convertir la carte en une séquence plate

{: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']

Je souhaite transmettre des données de séquence à une fonction qui reçoit des arguments de longueur variable

(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'

Appliquer la fonction à tous les éléments de la séquence et supprimer nil

(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]

Je veux savoir si une valeur est booléenne

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

Si une valeur non nulle est trouvée parmi plusieurs candidats, la valeur est renvoyée.

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.

Je veux voir si la séquence est vide

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

Je veux associer / dissocier uniquement lorsque les conditions sont remplies pour la carte, et le renvoyer tel quel

(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.

Je veux arrêter de réduire au milieu

(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

Je souhaite appliquer une fonction (map) à toutes les clés (valeurs) d'une map

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}

Je souhaite supprimer des éléments d'un vecteur basé sur un index

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]

Je veux faire d'une instance de java.util.LinkedList un vecteur

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.

Je souhaite conserver une valeur qui se met à jour plusieurs fois entre les boucles

Il s'agit généralement d'une boucle for.

Je veux une base de données simple qui puisse être référencée tout au long du programme

Ignorez-le car la source dit "Je ne le recommande pas beaucoup".

Supprimer les valeurs fausses de la liste

(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}]

Indexer la liste des objets

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']

Obtenez le premier qui correspond à la condition de la séquence

(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))

Résumé

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

J'ai essayé un langage fonctionnel avec Python
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
J'ai essayé webScraping avec python.
J'ai fait une loterie avec Python.
J'ai essayé d'exécuter prolog avec python 3.8.2.
J'ai créé un démon avec Python
J'ai essayé la communication SMTP avec Python
J'ai essayé de simuler la probabilité d'un jeu de bingo avec Python
J'ai essayé d'écrire dans un modèle de langage profondément appris
J'ai fait un compteur de caractères avec Python
J'ai dessiné une carte thermique avec Seaborn [Python]
J'ai essayé le rendu non réaliste avec Python + opencv
J'ai essayé la récurrence avec Python ② (séquence de nombres Fibonatch)
Ce que j'ai fait avec les tableaux Python
J'ai fait une carte hexadécimale avec Python
J'ai essayé le traitement du langage naturel avec des transformateurs.
J'ai fait un jeu rogue-like avec Python
J'ai fait un simple blackjack avec Python
J'ai créé un fichier de configuration avec Python
# J'ai essayé quelque chose comme Vlookup avec Python # 2
J'ai fait un simulateur de neurones avec Python
[5e] J'ai essayé de créer un certain outil de type Authenticator avec python
[2nd] J'ai essayé de créer un certain outil de type Authenticator avec python
[3ème] J'ai essayé de créer un certain outil de type Authenticator avec python
[Python] Un mémo que j'ai essayé de démarrer avec asyncio
J'ai essayé de créer une liste de nombres premiers avec python
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai essayé de créer une application de notification de publication à 2 canaux avec Python
J'ai essayé de créer une application todo en utilisant une bouteille avec python
[4th] J'ai essayé de créer un certain outil de type Authenticator avec python
[1er] J'ai essayé de créer un certain outil de type Authenticator avec python
J'ai essayé Python> décorateur
J'ai essayé de "lisser" l'image avec Python + OpenCV
J'ai essayé des centaines de millions de SQLite avec python
J'ai créé une application graphique avec Python + PyQt5
J'ai essayé de "différencier" l'image avec Python + OpenCV
J'ai essayé de jouer à un jeu de frappe avec Python
J'ai essayé de créer un bloqueur de filles pourries sur Twitter avec Python ①
J'ai essayé L-Chika avec Razpai 4 (édition Python)
[Python] J'ai joué avec le traitement du langage naturel ~ transformers ~
[Python] J'ai créé un téléchargeur Youtube avec Tkinter.
J'ai essayé la différenciation jacobienne et partielle avec python
J'ai essayé d'obtenir des données CloudWatch avec Python
J'ai essayé d'utiliser mecab avec python2.7, ruby2.3, php7
J'ai essayé la synthèse de fonctions et le curry avec python
J'ai essayé de sortir LLVM IR avec Python
J'ai essayé de "binariser" l'image avec Python + OpenCV
J'ai essayé d'utiliser Pythonect, un langage de programmation de flux de données.
J'ai essayé de lire un fichier CSV en utilisant Python
J'ai essayé d'exécuter faiss avec python, Go, Rust
J'ai essayé d'automatiser la fabrication des sushis avec python