Un peu plus de détails sur la notation d'inclusion de python

À propos de la notation d'inclusion de python

[nbviewer] Également publié sur (http://nbviewer.jupyter.org/format/slides/github/y-sama/comprehension/blob/master/comprehension.ipynb#/).

En parlant de python, c'est une notation inclusive. <= Préjugé? Cependant, il est difficile à lire à moins que vous ne vous y habituiez, j'ai donc essayé de résumer comment le lire un peu plus en détail.

Génération de liste normale

extension_1 = []
for i in range(10):
    extension_1.append(i)
extension_1
#>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Notation d'inclusion de liste

Syntaxe de base [counter for counter in iterator] J'écris souvent seulement [i for i in] d'abord, puis je le modifie. Lors de la génération d'une liste équivalente à extension_1 en notation d'inclusion

comprehension_1= [i for i in range(10)]
comprehension_1
#>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

la vitesse

Comparons la vitesse d'exécution de l'utilisation ou non de la notation d'inclusion de liste. Il a été mesuré en utilisant la magie cellulaire de jupyter %% timeit.

%%timeit
extension_1 = []
for i in range(10000):
    extension_1.append(i)
#>>> 100 loops, best of 3: 3.37 ms per loop
%%timeit
comprehension_1= [i for i in range(10000)]
#>>> 1000 loops, best of 3: 1.05 ms per loop

** L'inclusion de liste rend non seulement le code plus propre, mais présente également un avantage en termes de vitesse ** Référence: Pourquoi la notation d'inclusion de Python est-elle si rapide? Il y a deux raisons principales pour être lent.

Le premier effet peut également être éliminé en poussant la référence hors de la boucle.

%%timeit
extension_1_ = []
append=extension_1_.append
for i in range(10000):
    append(i)
#>>> 1000 loops, best of 3: 1.57 ms per loop

On dit généralement que la vitesse d'exécution est doublée lorsque la liste est incluse, mais environ 80% de celle-ci est due à la surcharge de la partie appel de la méthode d'ajout.

En incluant if (postfix if)

Il n'y a pas d'instruction postfix if en python, mais vous ne pouvez (par conséquent) écrire que la notation d'inclusion de liste.

extension_2 =[]
for i in range(10):
    if i%2==0:
        extension_2.append(i)
extension_2
#>>> [0, 2, 4, 6, 8]

Si vous réécrivez l'extension_2 dans la notation d'inclusion de liste, cela ressemble à ce qui suit.

comprehension_2 = [i for i in range(10) if i%2==0]
comprehension_2
#>>> [0, 2, 4, 6, 8]

Le résultat est une syntaxe if de suffixe, car la notation inclusive implique une clause for suivie d'une clause if ou d'une clause for. (Imaginez que vous puissiez omettre les deux points et le retrait.)

Avec l'indentation, l'image est la suivante.

[
i
for i in range(10)
  if i%2==0
]

J'expliquerai un peu plus en détail dans Dark Edition. ..

%%timeit
extension_2 =[]
for i in range(10000):
    if i%2==0:
        extension_2.append(i)
#>>> 100 loops, best of 3: 4.08 ms per loop
%%timeit
comprehension_2 = [i for i in range(10000) if i%2==0]
#>>> 100 loops, best of 3: 3.15 ms per loop
%%timeit
extension_2_ =[]
append=extension_2_.append
for i in range(10000):
    if i%2==0:
        append(i)
#>>> 100 loops, best of 3: 3.81 ms per loop

** En fait, si le taux de calcul est déterminant, donc même si vous forcez la notation d'inclusion de liste, la vitesse ne s'améliorera que d'environ 20 à 30%. ** **

Si si ~ else est inclus (opérateur conditionnel)

C'est déroutant, mais ** s'il contient une clause else, la position de if change car l'opérateur conditionnel (l'opérateur ternaire en d'autres termes) est utilisé ** (Les opérateurs conditionnels ne sont pris en charge qu'après Python 2.5)

extension_3 =[]
for i in range(10):
    if i%2==0:
        extension_3.append(i)
    else:
        extension_3.append(str(i))
extension_3
#>>> [0, '1', 2, '3', 4, '5', 6, '7', 8, '9']
comprehension_3 = [ i if i%2==0 else str(i) for i in range(10)]
comprehension_3
# >>> [0, '1', 2, '3', 4, '5', 6, '7', 8, '9']

Cela peut être plus facile à comprendre si vous pensez que cela équivaut à cela

extension_3_cond =[]
for i in range(10):
    extension_3_cond.append(i) if i%2==0 else extension_3_cond.append(str(i))
extension_3_cond
#>>> [0, '1', 2, '3', 4, '5', 6, '7', 8, '9']

J'obtiens une erreur lorsque j'ajoute if ~ else après avoir été tiré par la façon d'écrire un suffixe if.

#Ne marche pas
[ i for i in range(10) if i%2==0 else str(i)]
#>>> SyntaxError: invalid syntax

Puisque si ~ else détermine le taux, il n'y a pas beaucoup d'accélération par la notation d'inclusion.

Notation d'inclusion de dictionnaire et notation d'inclusion d'ensemble

Dans python2.7 ou version ultérieure, les inclusions de dictionnaire et les inclusions d'ensemble peuvent également être utilisées comme des notations d'inclusion autres que des listes.

comprehension_dict = {str(i):i for i in range(10)}
print(comprehension_dict)
#>>> {'7': 7, '8': 8, '2': 2, '9': 9, '0': 0, '1': 1, '6': 6, '5': 5, '4': 4, '3': 3}

Ça va bien avec le zip.

label = ["kinoko", "takenoko", "suginoko"]
feature = ["yama", "sato", "mura"]
{i:j for i,j in zip(label,feature)}
#>>> {'kinoko': 'yama', 'suginoko': 'mura', 'takenoko': 'sato'}

Si vous passez simplement la clé et la valeur comme dans ce cas, vous n'avez pas besoin d'utiliser la notation d'inclusion. dict(zip(label,feature))

Jusqu'à python2.6, je passerai tuple à dict.

comprehension_dict2 = dict((str(i),i) for i in range(10))
print(comprehension_dict2)

Vous pouvez également utiliser postfix si.

comprehension_dict2 = {str(i):i for i in range(10) if i%2==0}
print(comprehension_dict2)
#>>> {'8': 8, '6': 6, '2': 2, '4': 4, '0': 0}

Vous pouvez également utiliser des opérateurs conditionnels. Puisqu'il s'agit d'un opérateur conditionnel, il doit être décrit dans chacune des clés et valeurs avant et après le ":".

comprehension_dict3 = {str(i) if i%2==0 else i : i if i%2==0 else str(i) for i in range(10)}
print(comprehension_dict3)
#>>> {'2': 2, 1: '1', 3: '3', 5: '5', '0': 0, 7: '7', 9: '9', '6': 6, '4': 4, '8': 8}

Cela ne marche pas. (Je l'ai fait avant orz)

#Ne marche pas
comprehension_dict4 = {str(i):i if i%2==0 else i:str(i) for i in range(10)}
#>>> SyntaxError: invalid syntax

Définir la notation d'inclusion

Si vous le placez entre {} sans deux-points, il sera inclus dans l'ensemble.

comprehension_set={i%5 for i in range(10)}
comprehension_set
#>>> {0, 1, 2, 3, 4}

Notez que {} avec zéro élément signifie un dictionnaire.

zero_set={}
type(zero_set)
# >>> dict

Expression de générateur et notation d'inclusion de tapple

Il est facile de se méprendre à partir de la syntaxe, mais même si vous l'entourez entre (), ce sera une expression de générateur au lieu d'une notation d'inclusion taple.

comprehension_gen=(i%5 for i in range(10))
comprehension_gen
#>>> <generator object <genexpr> at 0x7f3000219678>

for i in comprehension_gen:print(i)
#>>> 0
#>>> 1
#>>> 2
#>>> 3
#>>> 4
#>>> 0
#>>> 1
#>>> 2
#>>> 3
#>>> 4

Au contraire, il est utilisé plutôt que la notation d'inclusion de tuple. Contrairement à la liste, il ne stocke pas tous les éléments en mémoire, mais génère l'élément suivant dans l'ordre. La façon d'écrire sans utiliser la notation d'inclusion est la suivante, mais c'est gênant car vous ne pouvez pas y aller à moins de créer une fonction qui génère un générateur une fois.

def gen_func():
    for i in range(10):
        yield i%5
extension_gen = gen_func()
extension_gen
#>>> <generator object gen_func at 0x7f3000166830>

Vous n'avez pas souvent besoin de la notation d'inclusion de tuple, mais si vous en avez vraiment besoin, vous pouvez la créer en transmettant la notation d'inclusion de liste à la fonction de tuple.

tuple([i for i in range(10)])
#>>> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

[Une addition] J'ajouterai le contenu du commentaire. Vous pouvez le transmettre au générateur, et le générateur peut omettre les parenthèses, donc je pense qu'il est facile à lire. (Il sera écrit comme une notation d'inclusion de tapple.)

tuple(i for i in range(10))
#>>> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

#Abréviation des parenthèses dans la syntaxe suivante
tuple((i for i in range(10)))

Comparaison avec la programmation fonctionnelle

Les notations de carte, de filtre et d'inclusion ont des résultats similaires et sont souvent comparées. De plus, dans la série python 2, la carte et le filtre renvoient une liste, donc cela correspond à la notation d'inclusion de liste. Dans la série python 3, il retourne des objets map et filter, donc il correspond au générateur.

Réécriture avec carte

map(lambda i:i**2,range(1,11))
# python2.Pour x
#>>> [1, 4, 9, 16, 25, 36, 49, 64, 100]
# python3.Dans le cas de x, l'itérateur nommé objet map est renvoyé.
#>>> <map at 0x4570f98>

list(map(lambda i:i**2,range(1,11)))
#>>> [1, 4, 9, 16, 25, 36, 49, 64, 100]

#S'il s'agit d'une notation d'inclusion de liste
[i**2 for i in range(1,11)]
#>>> [1, 4, 9, 16, 25, 36, 49, 64, 100]

Réécriture avec filtre

filter(lambda i:i%2==1, range(1,11))
# python2.Pour x
#>>> [1, 3, 5, 7, 9]
# python3.Pour x, il renvoie un itérateur nommé Filter Object
#>>> <filter at 0x4578a20>

list(filter(lambda i:i%2==1, range(1,11)))
#>>> [1, 3, 5, 7, 9]
#S'il s'agit d'une notation d'inclusion de liste
[i for i in range(1,11) if i%2==1]
#>>> [1, 3, 5, 7, 9]

Lorsqu'il est imbriqué

map(lambda j:j**2, filter(lambda i:i%2==1, range(1,11)))
# python2.Pour x
#>>> [1, 9, 25, 49, 81]
# python3.Dans le cas de x, l'objet filtre est renvoyé
#>>> <filter at 0x4578a20>

list(map(lambda j:j**2, filter(lambda i:i%2==1, range(1,11))))
#>>> [1, 9, 25, 49, 81]

#S'il s'agit d'une notation d'inclusion de liste
[i**2 for i in range(1,11) if i%2==1]
#>>> [1, 9, 25, 49, 81]

La notation d'inclusion de liste est plus facile à lire pour moi, mais est-ce une question de familiarité? En outre, l'inclusion de liste est généralement plus rapide.

Route vers les ténèbres

** Après avoir lu cette section, nous vous recommandons de lire le Code lisible pour purifier votre esprit. ** ** Je pense qu'il est pythonique de ne pas utiliser de branchement conditionnel ou à étapes multiples autre que la notation d'inclusion de base.

Connectez plusieurs opérateurs conditionnels

Connectez plusieurs opérateurs conditionnels En prenant fizzbuzz comme exemple, cela ressemble à ceci.

fizzbuzz=[]
for i in range(1,16):
    if i%15==0:
        fizzbuzz.append("fizzbuzz")
    elif i%3==0:
        fizzbuzz.append("fizz")
    elif i%5==0:
        fizzbuzz.append("buzz")
    else:
        fizzbuzz.append(i)
#>>> [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz']
["fizzbuzz" if i%15==0 else "fizz" if i%3==0 else "buzz"
 if i%5==0 else i for i in range(1,16)]
#>>> [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz']

Emboîté (plusieurs tableaux)

Je pense qu'il existe de nombreux cas où vous souhaitez imbriquer un tableau. Vous pouvez le faire en imbriquant la notation d'inclusion de liste dans la notation d'inclusion de liste.

outer_list=[]
for i in range(3):
    innter_list=[]
    for j in range(10):
        innter_list.append(j)
    outer_list.append(innter_list)
outer_list
#>>> [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
#>>>  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
#>>>  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]

#Si vous écrivez en notation d'inclusion de liste
[[j for j in range(10)] for i in range(3)]
#>>> [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
#>>>  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
#>>>  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]

Quand il s'agit de triplets, cela devient difficile à lire même s'il s'agit de python.

Double boucle

Prenez aplatir comme exemple. Ce n'est pas si difficile à lire une fois que vous l'avez compris, À première vue, la lisibilité est considérablement réduite.

init=[[1,2,3],[4,5],[6,7]]
flatten=[]
for outer in init:
    for inner in outer:
        flatten.append(inner)
flatten
#>>> [1, 2, 3, 4, 5, 6, 7]

#Équivalent à cela
[inner for outer in init for inner in outer]
#>>> [1, 2, 3, 4, 5, 6, 7]

En gros, lisez dans l'ordre la clause for sur le côté gauche, et la dernière chose à mettre dans la liste vient à l'esprit. Si vous voulez mettre en retrait, cela ressemble à ceci.

[
inner
for outer in init
    for inner in outer
]
#>>> [1, 2, 3, 4, 5, 6, 7]

[Y compris if (postfix if) indiqué dans la section](http://qiita.com/y__sama/items/a2c458de97c4aa5a98e7#if%E3%82%92%E5%90%AB%E3%82%80% Semblable à E5% A0% B4% E5% 90% 88% E5% BE% 8C% E7% BD% AEif), il se comporte comme omettre les deux points et le retrait pour chaque clause for.

Patatoku Kashii

En combinant zip et double boucle, vous pouvez générer Patatoku Cassie avec une doublure.

patato=[]
for i in zip("Voiture Pat","Taxi"):
    for j in i:
        patato.append("".join(j))
"".join(patato)
#>>> 'Patatoku Kashii'

#Si vous écrivez dans la notation d'inclusion
"".join(["".join(j) for i in zip("Voiture Pat","Taxi") for j in i])
#>>> 'Patatoku Kashii'

#Lorsqu'il est en retrait
"".join(
  [
  "".join(j)
  for i in zip("Voiture Pat","Taxi")
    for j in i
  ]
)
#>>> 'Patatoku Kashii'

Vous pouvez également mettre en impression.

[print(k) for i in zip("Voiture Pat","Taxi") for j in i for k in j]
#>Pennsylvanie
#>Ta
#>À
#>Ku
#>Puissance
#>Shi
#>-
#>-
#>>> [None, None, None, None, None, None, None, None]
#Il n'y a pas de valeur de retour pour la fonction d'impression, il s'agit donc d'un assortiment de None.

Technique de correspondance de boucles multiples avec clause if

C'est plutôt bon. Si vous ajoutez plusieurs tableaux ou lambda à cela, ce sera agréable à lire.

import re
DIO=["U","Inutile","RR","Pauvre","Y"]

rslt=[]
for i in DIO:
    if re.match("[URY]+",i):
        for j in i:
            rslt.append(j*2)
"".join(rslt)
#>>> 'UURRRRYY'

#Notation d'inclusion
"".join([j*3 for i in DIO if re.match("[URY]+",i) for j in i])
#>>> 'UUURRRRRRYYY'

#Lorsqu'il est en retrait, il ressemble à ceci
"".join(
  [
    j*4
    for i in DIO
      if re.match("[URY]+",i)
        for j in i
  ]
)
#>>> 'UUUURRRRRRRRYYYY'

Recommended Posts

Un peu plus de détails sur la notation d'inclusion de python
Gestion des exceptions Python un peu plus pratique
Un peu plus sur le FIFO
Construire un environnement Python sur Mac
Construire un environnement Python sur Ubuntu
Créer un environnement Python sur Mac (2017/4)
Créer un environnement python3 sur CentOS7
Un peu plus sur les références ~ Prenant Python et Java comme exemples ~
Construire un environnement python sur MacOS (Catallina)
Créez un environnement python sur votre Mac
Un mémo contenant Python2.7 et Python3 dans CentOS
Carte des informations de location sur une carte avec python
Exécutez le code Python sur A2019 Community Edition
Créer un environnement Python + OpenCV sur Cloud9
[Python] Une barre de progression sur le terminal
Python sur Windows
twitter avec python3
Créez simplement un environnement d'exécution Python 3 sous Windows
Créez un environnement python avec ansible sur centos6
Créer un environnement Python sur Mac (Mountain Lion)
Folium: Visualisez les données sur une carte avec Python
Créez un environnement de développement Python sur votre Mac
python sur mac
Une histoire sur l'exécution de Python sur PHP sur Heroku
[Venv] Créer un environnement virtuel python sur Ubuntu
Un mémorandum pour toucher Python Flask avec Heroku
Configurer un environnement de développement Python sur Marvericks
Python sur Windbg
Construire un environnement Python sur le serveur Sakura VPS
Décrypter une chaîne chiffrée sur iOS avec Python
Créer un environnement d'exécution Python sur IBM i
Visualiser grib2 sur une carte avec python (matplotlib)
Construire un environnement de développement Python sur Raspberry Pi
J'ai fait un peu de recherche sur la classe
Une petite histoire à savoir comme un point addictif lors de l'écriture d'applications Twilio à l'aide de Python sur AWS Lambda
Déployer des applications Web Python 3.6 / Django / Postgres sur Azure
Créer un environnement de développement Python basé sur GVim sur Windows 10 (3) GVim8.0 et Python3.6
# 2 Créez un environnement Python avec une instance EC2 d'AWS (ubuntu18.04)
Python Ver. Présentation de WebPay avec un peu de code
Créer un environnement Python d'apprentissage automatique sur Mac OS
Construire l'extension Python E-Cell 4 sur Windows 7 (64 bits)
Un mémo pour créer un environnement de développement python avec macOS Catalina
Jusqu'à dessiner un graphe 3D avec Python dans Windows10
Créez un environnement de développement Python 3 (Anaconda) confortable avec Windows
Déployer l'application Django sur Google App Engine (Python3)
Faire un point d'arrêt sur la couche c avec python
J'ai créé un environnement Python3 sur Ubuntu avec direnv.
Créer un environnement de développement Python basé sur GVim sur l'installation de Windows 10 (1)
Comment créer un environnement Django (python) sur Docker
Créer un environnement de développement Python sur Mac OS X
Lire un peu plus arch / arm / boot / compressé / Makefile
Créez un environnement Python sur votre Mac en utilisant pyenv
Procédure de création d'un environnement CDK sous Windows (Python)
Ecrire un histogramme à l'échelle logarithmique sur l'axe des x en python
Créer un environnement de développement Python à l'aide de pyenv sur MacOS
Remarques sur l'accélération du code Python avec Numba