[Feature Poem] Je ne comprends pas le langage fonctionnel Vous pouvez le comprendre avec Python: Partie 1 Les fonctions qui reçoivent des fonctions sont pratiques.

Ceci est un ** poème caractéristique ** qui décrit les fonctionnalités de la programmation fonctionnelle en Python. Les belles filles IQ145 n'apparaîtront pas, alors ne vous attendez pas à trop.

[Lecteurs cibles]

[Article de la série]

introduction

Il y a une phrase "Pourquoi la programmation de fonctions est importante". Comme le titre l'indique, c'est une phrase qui présente l'utilité d'un langage fonctionnel. C'est long, mais ça ressemble à ça en 3 lignes:

Cependant, bien que cette phrase et ce contenu soient très évalués, ** la bonté du langage fonctionnel s'explique par le code du langage fonctionnel, il n'est donc pas transmis aux utilisateurs qui ne connaissent pas du tout le langage fonctionnel **. J'ai un problème.

Lorsque vous expliquez à quelqu'un qui ne connaît pas les langages fonctionnels, pourquoi essayez-vous d'expliquer en utilisant uniquement des langages fonctionnels (j'aurais aimé avoir également écrit le code pour d'autres langages populaires)? C'est exactement comme "** Si vous ne comprenez pas les termes techniques et demandez au programmeur, ils seront expliqués en termes techniques plus difficiles **". Même si vous voulez connaître le langage fonctionnel et lire cette phrase, vous n'aurez que l'impression que le langage fonctionnel est difficile.

Par conséquent, dans ce poème, les «fonctions d'ordre supérieur» et «l'évaluation retardée», qui sont considérées comme particulièrement importantes dans «Pourquoi la programmation de fonctions est importante», seront expliquées en Python. Je vais l'expliquer sans utiliser le code du langage fonctionnel, donc il sera facile pour les personnes qui ne sont pas des utilisateurs du langage fonctionnel de le comprendre.

(Hé, là! Ne dites pas: "N'y a-t-il pas moins d'utilisateurs de Python japonais que d'utilisateurs de langage fonctionnel?")

Préparation pour expliquer les fonctions d'ordre supérieur

Il est difficile d'expliquer soudainement la fonction d'ordre supérieur, alors préparons-nous avant cela.

Objet de fonction

En Python, ** les fonctions sont des objets **.

Par exemple, l'état réel de la ** définition de fonction comme suit est l'opération ** de "création d'un objet fonction et de son affectation à une variable".

##Un objet fonction est créé et affecté à la variable bonjour
def hello(name):
  print("Hello %s!" % name)

##Si vous regardez le contenu de la variable hello, vous pouvez voir qu'il s'agit d'un objet fonction.
print(hello)    #Résultat de l'exécution:<function hello at 0x1007a3ed8>

Par conséquent, vous pouvez appeler la fonction en affectant le contenu de la variable «bonjour» à une autre variable.

##Le contenu de la variable hello peut être affecté à une autre variable et peut être appelé.
say = hello     #Attribuer l'objet fonction à une autre variable
say("world")    #Appeler(Le résultat est bonjour("world")Pareil que)

En plus de def, vous pouvez également créer des objets de fonction avec lambda. La différence entre les deux est la suivante:

##La fonction définie par def est
def add(x, y):
  return x + y
print(add(3, 5))      #=> 8

##Vous pouvez également écrire avec lambda(Cependant, uniquement dans le cas d'une seule formule)
add = lambda x, y: x + y    #Vous n'avez pas à écrire de retour
print(add(3, 5))      #=> 8

##def contient plusieurs instructions, mais doit être indépendant et unique
def sum(numbers):
  t = 0                 #Cette fonction contient plusieurs instructions, donc
  for n in numbers:     #Impossible d'écrire avec lambda
    t += n
  return t

##lambda ne peut être qu'une seule expression, mais elle peut être intégrée dans d'autres instructions et expressions
sorted(strings, lambda s: len(s))  #Exemple d'incorporation de lambda dans l'argument de fonction

L'important est qu'en Python, les fonctions sont des objets, vous pouvez donc les traiter comme des données ** comme des entiers et des chaînes. Puisque vous pouvez traiter la fonction comme des données, vous pouvez faire quelque chose comme ceci:

##Les fonctions peuvent être traitées comme des données (comme s'il s'agissait d'entiers ou de chaînes)
n = 123       #Attribuer un entier à une variable
s = "ABC"     #Attribuer une chaîne à une variable
f = hello     #Attribuer une fonction à une variable

##Passer une fonction comme argument à une autre fonction
otherfunc(hello)

##Créer et renvoyer une nouvelle fonction dans une fonction
def create_func():
  def add(x, y):
    return x + y
  return add
  ##Ou c'est bien
  #return lambda x, y: x + y

Résumé ici:

Ce que représente la fonction

Même si vous dites "fonction" en un mot, il y a différents contenus qu'il représente. Ici, j'ai essayé de les classer dans les trois suivants.

** (A) Formule de calcul / formule de conversion **… Calcule une valeur en une autre. Ou convertissez une valeur en une autre.

##Calculer la valeur double(Convertir en double valeur)
def double(x):
  return x * 2

##Calculer la somme des arguments(Convertir en somme d'arguments)
def add(x, y):
  return x + y

##Calculer le nom de la classe HTML en fonction du numéro de ligne(Convertir les numéros de ligne en noms de classe HTML)
def classname(index):
  if index % 2 == 0:
    return "row-even"
  else:
    return "row-odd"

** (B) Expression conditionnelle / Expression de jugement **… Juge si la valeur satisfait à la condition. Renvoie vrai s'il se rencontre, faux s'il ne le fait pas. (Remarque: Python utilise True / False au lieu de true / false.)

##Déterminez si c'est pair
def is_even(n):
  return n % 2 == 0    #Vrai pour pair, Faux pour impair

##Déterminez s'il est vide
def is_blank(line):
  if not line:         #Renvoie True si aucun ou une chaîne vide
    return True
  if not line.strip(): #Renvoie True si seuls les espaces ou les caractères de saut de ligne
    return True
  return False         #Sinon, renvoie False

##Qu'ils soient amoureux ou non(Vers Teketou)juge
couples = [
  ("Kirito", "Asuna"),
  ("Courageux",   "Diable"),
  ("Naruto", "Hinata"),
  ("Ellen", "Mikasa"),   #L'objection n'est pas reconnue
  ("Frère", "Neige épaisse"),
  ("Kyon", "Sasaki"),   #J'admets l'objection
]
def is_couple(boy, girl):
  return (boy, girl) in couples

** (C) Traitement / Procédure **… Sortie d'une chaîne de caractères, lecture d'un fichier, etc.

##Processus pour afficher le nom
def hello(name):
  print("Hello %s!" % name)

##Traitement pour lire un fichier et compter le nombre de lignes
## (Remarque: l'instruction with ferme automatiquement le fichier ouvert)
def count_lines(filename):
  n = 0
  with open(filename) as f:
    for line in f:
      n += 1
  print("%s lines" % n)

Cependant, cette classification n'est pas stricte. Veuillez noter qu'il ne s'agit que d'une classification approximative à utiliser dans les explications qui suivent.

Aussi, je veux vraiment expliquer les effets secondaires ici, mais si je dis "quels sont les effets secondaires?", Cela dépasse la portée de ce poème et la capacité de l'auteur, donc j'omettrai l'explication ici (j'aime les termes techniques comme ça). Les gens intelligents le feront).

Résumé ici:

Rôle des arguments dans les fonctions / procédures / sous-programmes

Par exemple, créons une "fonction qui fait la somme de 1 à 10". (Remarque: range (1, 11) produit des entiers de 1 à 10, pas jusqu'à 11.)

def total():
  t = 0
  for i in range(1, 10+1):
    t += i
  return t

C'est trop facile.

Cependant, vous n'écririez normalement pas ceci, mais utilisez plutôt un argument pour en faire une "fonction qui fait la somme de 1 à n".

def total(n):
  t = 0
  for i in range(1, n+1):
    t += i
  return t

Vous pouvez également utiliser "une fonction qui additionne m à n".

def total(m, n):    #Vérification d'argument omise
  t = 0
  for i in range(m, n+1):
    t += i
  return t

En regardant ceci:

De cette façon, dans les fonctions / procédures / sous-programmes, vous pouvez créer une partie variable ** (ou augmenter) en utilisant des ** arguments (en gros, mais si vous connaissez le moteur de modèle, je pense que c'est similaire à cela. N'est-ce pas?). De plus, plus il y a de pièces variables, plus la gamme d'applications est large.

Et si vous transmettez non seulement des données telles que des valeurs numériques, des chaînes de caractères, des valeurs booléennes et des tableaux, mais aussi des ** formules de calcul / formules de conversion, des formules conditionnelles / formules de jugement et des traitements / procédures à la partie variable de la fonction, la plage d'application sera encore élargie. Propagé **. Vous pouvez le faire avec un objet fonction.

À propos des fonctions qui reçoivent des fonctions (fonctions d'ordre supérieur)

Les fonctions d'ordre supérieur sont des fonctions qui traitent la fonction comme des données. Plus précisément, cela ressemble à ceci:

(Bien sûr, "une fonction qui reçoit une fonction et renvoie une fonction" est également une fonction d'ordre supérieur.)

Parmi ceux-ci, ce poème décrit la première "fonction qui reçoit une fonction".

Les fonctions d'ordre supérieur qui reçoivent des fonctions peuvent être classées grossièrement comme suit.

Regardons-les avec des exemples concrets.

Fonctions d'ordre supérieur qui reçoivent des formules / formules de conversion

Jetez un œil au code suivant. Les deux fonctions font des choses différentes.

##Une fonction qui prend un tableau d'entiers et double chaque élément
def doubles(arr):
  newarr = []
  for x in arr:
    newarr.append(x * 2)      #Double chaque élément
  return newarr

##Une fonction qui prend un tableau de chaînes, convertit chaque élément en majuscule et le renvoie
def uppers(arr):
  newarr = []
  for x in arr:
    newarr.append(x.upper())  #Capitaliser chaque élément
  return newarr

(Remarque: en Python, il est appelé "liste" au lieu de "tableau". Bien qu'il soit appelé "liste", ce n'est pas une liste concaténée, mais un tableau de longueur variable dans d'autres langages (Java java.util.ArrayList et Ruby). Array). Veuillez noter que ce poème n'est pas destiné à expliquer Python, nous osons donc l'appeler "tableau" en tenant compte des autres utilisateurs de langage.)

Maintenant, les deux fonctions font des choses différentes, mais elles font des choses très similaires. ** La seule différence est la formule / formule de conversion passée à newarr.append () **.

Par conséquent, nous allons transformer la partie commune en une fonction appelée map () et passer la partie différente en fonction:

##Formule pour chaque élément du tableau/Fonction pour appliquer la formule de conversion
def map(func, arr):
  newarr = []
  for x in arr:
    newarr.append(func(x))      #Formule de calcul pour chaque élément/Appliquer la formule de conversion
  return newarr

##Une fonction qui prend un tableau d'entiers et double chaque élément
def doubles(arr):
  def func(x): return x * 2     #une formule/En utilisant la formule de conversion,
  return map(func, arr)         #Appeler une fonction commune
  ##Ou
  #return map(lambda x: x * 2, arr)

##Une fonction qui prend un tableau de chaînes, convertit chaque élément en majuscule et le renvoie
def uppers(arr):
  def func(x): return x.upper() #une formule/En utilisant la formule de conversion,
  return map(func, arr)         #Appeler une fonction commune
  ##Ou
  #return map(lambda x: x.upper(), arr)

Ainsi, map () est une "fonction d'ordre supérieur qui reçoit une formule de calcul / conversion en tant que fonction". De plus, en utilisant des fonctions d'ordre supérieur telles que map (), un traitement commun peut être créé et le code est simplifié.

Résumé ici:

Notez qu'en Python, map () est intégré par défaut, vous n'avez donc pas à le définir vous-même. De plus, map () de Python peut être utilisé non seulement pour les tableaux mais aussi pour les chaînes et les fichiers, mais ce n'est pas le but de ce poème, donc je vais l'omettre.

Fonction d'ordre supérieur qui reçoit des expressions conditionnelles / de jugement

Jetez un œil au code suivant. Les deux fonctions font des choses différentes.

##Une fonction qui prend un tableau d'entiers et sélectionne et renvoie uniquement des nombres pairs
def evens(arr):
  newarr = []
  for x in arr:
    if x % 2 == 0:           #Choisissez seulement même
      newarr.append(x)
  return newarr

##Reçoit un tableau de chaînes et se termine".html"Une fonction qui sélectionne uniquement ceux qui sont
def shorts(arr):
  newarr = []
  for x in arr:
    if x.endswith(".html"):  #La fin est".html"Choisissez ce que c'est
      newarr.append(x)
  return newarr

(Remarque: en Python, il est appelé "liste" au lieu de "tableau", mais veuillez noter que ce poème est intentionnellement appelé "tableau" en tenant compte des utilisateurs d'autres langues.)

Ces deux fonctions font également des choses différentes, mais elles font des choses très similaires. ** La seule différence est l'expression conditionnelle / expression de jugement spécifiée dans l'instruction if **.

Par conséquent, la partie commune est une fonction appelée filter (), et la partie différente est passée en tant que fonction:

##Expression conditionnelle de chaque élément du tableau/Une fonction qui sélectionne et renvoie uniquement celles qui satisfont à la formule de jugement
def filter(func, arr):
  newarr = []
  for x in arr:
    if func(x):             #Expression conditionnelle/Sélectionnez uniquement les éléments qui satisfont à la formule de jugement
      newarr.append(x)
  return newarr

##Une fonction qui prend un tableau d'entiers et sélectionne et renvoie uniquement des nombres pairs
def evens(arr):
  def func(x): return x % 2 == 0    #Expression conditionnelle/Faire de la formule de jugement une fonction
  return filter(func, arr)          #Appeler une fonction commune
  ##Ou
  #return filter(lambda x: x % 2 == 0, arr)

##Reçoit un tableau de chaînes et se termine".html"Une fonction qui sélectionne uniquement ceux qui sont
def htmls(arr):
  def func(x): return x.endswith(".html")  #Expression conditionnelle/Faire de la formule de jugement une fonction
  return filter(func, arr)                 #Appeler une fonction commune
  ##Ou
  #return filter(lambda x: x.endswith(".html"), arr)

Ainsi, filter () est une "fonction d'ordre supérieur qui reçoit des expressions conditionnelles / de jugement sous forme de fonctions". Et j'ai pu simplifier le code en utilisant des fonctions d'ordre supérieur comme filter ().

Résumé ici:

Notez que Python fournit également filter () en standard, vous n'avez donc pas besoin de le définir vous-même. Le standard Python filter () peut être utilisé non seulement pour les tableaux mais aussi pour les chaînes de caractères et les fichiers, mais il est hors de la portée de ce poème, donc les explications sont omises.

Fonction d'ordre supérieur qui reçoit un traitement / une procédure

Jetez un œil au code suivant. Nous faisons des benchmarks séparés avec les deux fonctions.

## (Pour Python 3)
try:
  xrange
except NameError:
  xrange = range

N = 1000000

import time

## str.join()Benchmark de la concaténation de chaînes en utilisant
def bench_strjoin():
  start = time.time()
  for _ in xrange(N):
    s = str.join("", ("Haruhi", "Kyon", "Mikuru", "Itsuki", "Yuki"))
  end = time.time()
  print("%.3f sec" % (end - start))

## '%'Benchant pour la concaténation de chaînes à l'aide d'opérateurs
def bench_percentop():
  start = time.time()
  for _ in xrange(N):
    s = "%s%s%s%s%s" % ("Haruhi", "Kyon", "Mikuru", "Itsuki", "Yuki")
  end = time.time()
  print("%.3f sec" % (end - start))

(Remarque: en Python, lors de l'utilisation de str.join (), il est courant d'écrire " ". Join ((...)). Cependant, cela semble si étrange pour les utilisateurs non-Python, donc j'utilise str.join (" ", (...)), ce qui est facile à comprendre pour les utilisateurs non-Python. )

En regardant ces deux fonctions, nous pouvons voir que:

Par conséquent, définissez une fonction appelée «benchmark ()» qui mesure le benchmark, et passez le contenu (traitement) du benchmark en fonction. Ensuite, le code ressemble à ceci:

## (Pour Python 3)
try:
  xrange
except NameError:
  xrange = range

N = 1000000

import time

##Une fonction qui mesure et affiche le temps d'exécution
def benchmark(func):
  start = time.time()
  func()               #Appelez le processus de référence
  end = time.time()
  print("%.3f sec" % (end - start))

## str.join()Benchmark de la concaténation de chaînes en utilisant
def bench_strjoin():
  def func():
    for _ in xrange(N):
      s = str.join("", ("Haruhi", "Kyon", "Mikuru", "Itsuki", "Yuki"))
  benchmark(func)

## '%'Benchant pour la concaténation de chaînes à l'aide d'opérateurs
def bench_percentop():
  def func():
    for _ in xrange(N):
      s = "%s%s%s%s%s" % ("Haruhi", "Kyon", "Mikuru", "Itsuki", "Yuki")
  benchmark(func)

##Remarque: pour le benchmark de déclaration()Y compris dans func()Coût d'appel
##Je ne fais pas ça ici parce que ça ne peut pas être ignoré.

Ainsi, «benchmark ()» est une «fonction d'ordre supérieur qui reçoit un processus / une procédure en tant que fonction». Grâce aux fonctions d'ordre supérieur, nous avons pu extraire des processus communs et simplifier le code.

Pour généraliser un peu plus cela, on peut dire que "** Le pré-traitement et le post-traitement peuvent être ajoutés en utilisant des fonctions d'ordre supérieur **". Par exemple:

Cela sera considéré.

Résumé ici:

Si vous souhaitez ajouter un pré-traitement et un post-traitement, il est courant d'utiliser l'instruction with en Python au lieu d'utiliser des fonctions d'ordre supérieur (décrites plus loin).

Fonctions d'ordre supérieur reçues dans les formules et les processus

Jetez un œil au code suivant. Les deux fonctions font des choses différentes.

##Une fonction qui prend un tableau d'entiers et renvoie une somme
def sum(arr):
  t = 0            #Valeur initiale: 0
  for x in arr:
    t = t + x      #Calculez le total(Pour une explication ultérieure, t+=Pas x)
  return t

##Une fonction qui reçoit un tableau de chaînes, le convertit en dictionnaire et le renvoie.
def to_dict(arr):
  t = {}           #Valeur initiale: dictionnaire vide
  for x in arr:
    t[x] = x       #Convertir en dictionnaire
    t = t          #Ceci est essentiellement inutile, mais ajouté pour explication
  return t

(Remarque: un «dictionnaire» en Python équivaut à «Hash» de Ruby et à «java.util.HashMap» de Java.)

Ces deux fonctions font également des choses différentes, mais elles font des choses très similaires. ** La seule différence est la valeur initiale et les formules et processus de la boucle **.

Par conséquent, les formules de calcul et les traitements dans la boucle sont transformés en fonctions. Ensuite, vous pouvez extraire la partie commune dans une fonction appelée réduire () comme suit:

##Effectuer des calculs ou traitements sur chaque élément du tableau et renvoyer les résultats empilés
def reduce(func, arr, initial):
  t = initial         #valeur initiale
  for x in arr:
    t = func(t, x)    #Effectuer des calculs et des traitements
  return t

##Une fonction qui prend un tableau d'entiers et renvoie une somme
def sum(arr):
  def func(t, x): return t + x      #Faire de la formule une fonction
  return reduce(func, arr, 0)       #Appeler une fonction commune
  ##Ou
  #return reduce(lambda t, x: t + x, arr, 0)

##Une fonction qui reçoit un tableau de chaînes, le convertit en dictionnaire et le renvoie.
def to_dict(arr):
  def func(t, x):                   #Faire du traitement une fonction
    t[x] = x
    return t
  return reduce(func, arr, {})      #Appeler une fonction commune

De cette façon, «réduire ()» est une «fonction d'ordre supérieur qui reçoit des formules et des processus comme des fonctions». À première vue, "calculer la somme" et "convertir en dictionnaire" devraient être des processus complètement différents, mais en fait, je ne pense pas que ce soit très intéressant que vous puissiez utiliser reduction () pour créer des parties communes. C'est ça?

À propos, la valeur initiale était requise pour «réduire ()» dans la définition ci-dessus. Cependant, en général, «reduction ()» peut omettre la valeur initiale, auquel cas le premier élément est utilisé comme valeur initiale. Le code ressemble à ceci:

class Undefined(object):
  pass           #Python pass signifie "ne rien faire"
undefined = Undefined()

def reduce(func, arr, initial=undefined):
  ##Si aucune valeur initiale n'est spécifiée, utilisez le premier élément à la place
  if initial is undefined:   # 'is'Est'=='Je pense que c'est une version plus rigoureuse de!
    t = undefined
    for x in arr:
      if t is undefined:
        t = x
      else:
        t = func(t, x)
    ##Cependant, si le tableau est vide, une erreur se produit(Parce que la valeur de retour ne sera pas définie)
    if t is undefined:
      raise TypeError("reduce() of empty sequence with no initial value")
    return t
  ##Si la valeur initiale est spécifiée, elle continuera comme avant
  else:
    t = initial
    for x in arr:
      t = func(t, x)
    return t

##Remarque:`t = initial`Quand`return t`Peut être facilement supprimé de l'instruction if,
##Je veux donner la priorité à la facilité de compréhension pour les débutants, alors laissez-le tel quel.

Dans ce cas, sum () peut être écrit comme suit (avec des noms d'argument différents), en omettant la valeur initiale.

def sum(arr):
  return reduce(lambda a, b: a + b, arr)

En écrivant ceci, ** l'opérateur "+" qui prend deux arguments peut être considéré comme s'il prenait n arguments **.

reduce()を使うと二項演算子があたかもn項演算子のように見える

Bien sûr, le contenu de reduction () ne fait que répéter l'opérateur "+" qui prend deux arguments plusieurs fois, mais selon le point de vue, l'opérateur qui prend n arguments n'est utilisé qu'une seule fois. C'est intéressant que ça ressemble à ça.

Résumé ici:

Notez que Python fournit également reduction () en standard et que vous n'avez pas besoin de le définir vous-même (bien que Python 3 nécessite de functools import reduction).

Combinez des fonctions d'ordre supérieur

Les fonctions d'ordre supérieur sont assez pratiques en elles-mêmes, mais elles sont encore plus pratiques lorsqu'elles sont combinées.

##Sortie de 1 à 10(1 <= x < 10+1)
nums = range(1, 10+1)
for x in nums:
  print(x)

##Sélectionnez et émettez uniquement des nombres impairs de 1 à 10
nums = range(1, 10+1)
for x in filter(lambda x: x%2 == 1, nums):
  print(x)

##Sélectionnez uniquement les nombres impairs de 1 à 10 et le carré et la sortie
nums = range(1, 10+1)
for x in map(lambda x: x*x, filter(lambda x: x%2 == 1, nums)):
  print(x)

##Sélectionnez uniquement les nombres impairs de 1 à 10, le carré et la somme
from functools import reduce    # python3
nums = range(1, 10+1)
total = reduce(lambda t, x: t+x,
               map(lambda x: x*x, filter(lambda x: x%2 == 1, nums)))
print(total)

##Ou
from functools import reduce    # python3
nums = range(1, 10+1)                      #De 1 à 10
nums = filter(lambda x: x%2 == 1, nums)    #Sélectionnez uniquement les nombres impairs,
nums = map(lambda x: x*x, nums)            #Au carré
total = reduce(lambda t, x: t+x, nums)     #Somme
print(total)

Mais pour être honnête, le «lambda» de Python n'est pas très facile à écrire. C'est beaucoup plus naturel d'écrire en Ruby, Groovy et Scala.

##Ruby peut écrire si naturellement
print (1..10).select {|x| x%2 == 1 }.map {|x| x*x }.reduce {|t,x| t+x }

En regardant ce code Ruby, il est facile de voir comment le processus se déroule dans l'ordre.

Si vous utilisez UNIX, vous remarquerez que cela ressemble beaucoup au traitement des tubes. En fait, si vous voulez comparer avec le traitement des tuyaux, vous devriez expliquer l'évaluation du retard, mais laissez-moi le faire à une date ultérieure.

Fonction de boucle vs d'ordre supérieur

Je republierai le code qui combine les fonctions d'ordre supérieur.

##Code qui combine des fonctions d'ordre supérieur
from functools import reduce    # python3
total = reduce(lambda t, x: t+x,
               map(lambda x: x*x, filter(lambda x: x%2 == 1, nums, 0)))
##Ou
nums = filter(lambda x: x%2 == 1, nums)    #Sélectionnez uniquement les nombres impairs,
nums = map(lambda x: x*x, nums)            #Au carré
total = reduce(lambda t, x: t+x, nums, 0)  #Somme

J'ai essayé d'écrire la même chose de manière procédurale en utilisant l'instruction for.

##Code écrit de manière procédurale à l'aide de l'instruction for
total = 0
for x in nums:
  if x%2 == 1:
    total += x*x

Eh bien, peu importe comment vous le regardez, l'instruction for est plus simple et plus facile à comprendre ...

En comparant ces deux codes, nous constatons que:

Code écrit de manière procédurale Code utilisant des fonctions d'ordre supérieur
Les boucles, les branches conditionnelles et les formules sont dans un seul bloc Le traitement est divisé en fonctions et elles sont combinées.
Manipulez les éléments du tableau un par un Gérez l'ensemble du tableau ensemble("Sélectionnez dans le tableau entier" "Carrez le tableau entier" "Sumulez le tableau entier" etc.)
Plus rapide (car il ne boucle qu'une seule fois et n'utilise pas d'appels de fonction) Le fonctionnement est lent(Parce que les boucles sont effectivement nécessaires trois fois pour flter, mapper et réduire, et le nombre d'appels de fonction est élevé.)

Le premier et le second sont particulièrement importants. En programmation fonctionnelle, c'est la façon de penser et de regarder les choses.

Pour compléter le troisième point, la combinaison de fonctions est certainement plus lente que ce que j'ai écrit en boucle, mais que cette lenteur compte est une autre affaire. Il existe de nombreux autres cas où le benchmark est plus lent mais l'expérience ne change pas, ou le goulot d'étranglement de vitesse se trouve dans une autre partie telle que les E / S.

Mauvaises nouvelles

Malheureusement, les fonctions d'ordre supérieur qui reçoivent des fonctions ne sont pas utilisées très souvent en Python. En effet, ce que vous pouvez écrire avec des fonctions d'ordre supérieur peut souvent être écrit plus naturellement par d'autres moyens.

Par exemple, il est plus naturel d'écrire «map ()» et «filter ()» en compréhension.

## map()Est
newarr = map(lambda x: x * x, arr)

##Vous pouvez écrire ceci dans la notation d'inclusion de liste
newarr = [ x * x for x in arr ]

## filter()Est
newarr = filter(lambda x: x % 2 == 0, arr)

##Vous pouvez écrire ceci dans la notation d'inclusion de liste
newarr = [ x for x in arr if x % 2 == 0 ]

Surtout lorsque vous combinez map () et filter (), la lisibilité de la notation d'inclusion se démarque.

## map()Et filtre()La combinaison de
newarr = map(lambda x: x * x, filter(lambda x: x % 2 == 0, arr))

##Vous pouvez écrire ceci dans la notation d'inclusion de liste
newarr = [ x * x for x in arr if x % 2 == 0 ]

Pour reduction (), vous pouvez utiliser la fonction sum () pour calculer la valeur totale, et vous pouvez utiliser la notation d'inclusion du dictionnaire pour convertir un tableau de chaînes en dictionnaire.

##Par exemple c'est
total = reduce(lambda t, x: t + x, arr, 0)

##C'est mieux, peu importe ce que tu penses
total = sum(arr)


##Par exemple c'est
def func(t, x):
  t[x] = x
  return t
dictionary = reduce(func, strings)

##Mieux vaut utiliser la notation d'inclusion de dictionnaire
dictionary = { x:x for x in strings }

Si vous souhaitez ajouter un prétraitement et un post-traitement, vous devez utiliser l'instruction with.

try:
  xrange                #Pour Python2
except NameError:
  xrange = range        #Pour Python3

N = 1000000

import time
from contextlib import contextmanager

@contextmanager         # '@'Est un décorateur de fonction(Commentaire à une date ultérieure)
def benchmark():
  start = time.time()
  yield                 # 'yield'Est pour le générateur(Commentaire à une date ultérieure)
  end = time.time()
  print("%.3f sec" % (end - start))

with benchmark():
  for _ in xrange(N):
    s = str.join("", ("Haruhi", "Kyon", "Mikuru", "Itsuki", "Yuki"))

with benchmark():
  for _ in xrange(N):
    s = "%s%s%s%s%s" % ("Haruhi", "Kyon", "Mikuru", "Itsuki", "Yuki")

Comme vous pouvez le voir, Python fournit beaucoup de fonctionnalités utiles, donc les fonctions d'ordre supérieur qui reçoivent les fonctions sont moins utilisées (pas du tout, sorted (arr, key = fn). ) ʻEt re.sub (modèle, fn, chaîne) ʻetc.).

En particulier, réduire () était une fonction intégrée dans Python2, mais dans Python3, elle ne peut être utilisée qu'en important depuis une bibliothèque. Il s'agit d'une rétrogradation de facto, et nous pouvons voir l'intention que "en Python, vous pouvez utiliser d'autres moyens que" réduire () "".

Cependant, les fonctions d'ordre supérieur qui génèrent les fonctions sont encore couramment utilisées. Cela sera expliqué dans le prochain Poème.

Histoire spécifique à Python

import operator

## '=='Equivalent à un opérateur
operator.eq(1+1, 2)   #=> True

## '+'Equivalent à un opérateur
operator.add(1, 2)    #=> 3

Des exercices

Écrivez un exemple de réponse dans la section des commentaires.

** [Problème 1] ** Définissons map (), filter () et reduction () par nous-mêmes.

** [Problème 2] ** La fonction parse_version (), qui convertit un numéro de version tel que"3.4.10"en un tableau d'entiers comme [3, 4, 10], estmap. Définissons-le en utilisant (). Comment utiliser:

print(parse_version("3.4.10"))   #=> [3, 4, 10]

(Indice: utilisez " 3.4.2 ".split (". ") Pour diviser la chaîne, et ʻint ("123") `pour convertir la chaîne en un entier.)

** [Problème 3] ** Utilisons filter () pour définir la fonction grep () qui sélectionne uniquement celles qui correspondent à l'expression régulière du tableau de chaînes de caractères. Comment utiliser:

arr = grep(r'\d+', ["ABC", "F102", "X10Y", "ZZZ"])
print(arr)   #=> ["F102", "X10Y"]

(Conseil: utilisez ʻimport re; m = re.search (r '.. pattern ..', string) `pour les expressions régulières.)

** [Problème 4] ** Définissons une fonction max_by () qui renvoie la valeur maximale par la méthode de comparaison spécifiée parmi les éléments du tableau en utilisant reduction (). Comment utiliser:

members = [
  ("Haruhi", "C"),   #Haruhi est C
  ("Mikuru", "E"),   #Mikuru est E
  ("Yuki",   "A"),   #Yuki est un
]

def getvalue(x):     #Retour seins
  return x[1]

##Qui a les plus gros seins?
ret = max_by(getvalue, members)
print(ret)   #=> ("Mikuru", "E")

(Ajout 08/02/2015: Le problème était faux! Je suis désolé!)

Résumé

J'ai expliqué en utilisant Python la fonction d'ordre supérieur qui reçoit la fonction.

en conclusion

En raison de la popularité des poèmes en langage fonctionnel, les langages fonctionnels attirent plus que jamais l'attention. C'est une opportunité unique, je voudrais donc profiter de cette opportunité pour promouvoir les fonctionnalités du langage fonctionnel de Python et Ruby et viser les ** intérêts des pêcheurs **.

Recommended Posts

[Feature Poem] Je ne comprends pas le langage fonctionnel Vous pouvez le comprendre avec Python: Partie 1 Les fonctions qui reçoivent des fonctions sont pratiques.
[Feature Poem] Je ne comprends pas le langage fonctionnel Vous pouvez le comprendre avec Python: Partie 2 La fonction qui génère la fonction est incroyable.
python Création de fonctions dont on pourra se souvenir plus tard
[Python] Je ne comprends pas ce que je fais avec la table [clé] [0] + = 1
Introduction à Python que même les singes peuvent comprendre (partie 3)
Introduction à Python que même les singes peuvent comprendre (partie 1)
Introduction à Python que même les singes peuvent comprendre (partie 2)
Il semble que vous puissiez maintenant écrire des livres de portail avec blueqat
N'écrivez pas Python si vous voulez l'accélérer avec Python
J'ai fait un package qui peut comparer des analyseurs morphologiques avec Python
J'ai fait un shuffle qui peut être réinitialisé (inversé) avec Python