[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.
extension_1 = []
for i in range(10):
extension_1.append(i)
extension_1
#>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
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]
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.
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%. ** **
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.
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
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
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)))
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.
** 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 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']
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.
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.
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.
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'