2016-12-09 1 views
2

J'ai une question étrange lors de l'utilisation de la boucle python. Cela peut être facile mais étrange pour moi. Dites si j'ai une liste de chaînes:Python boucle de cordes - pourquoi le «aucun» vient?

seqs=['AA', 'AT'] 

Puis je veux imprimer des éléments dans la liste. Une façon (méthode 1) est d'utiliser pour la boucle:

for seq in seqs: 
    print seq 

Qui fonctionne bien. Pendant ce temps, je définis une fonction « d'impression » (méthode 2) pour imprimer:

def print0(s): 
    print s 

[print0(s) for s in seqs] 

Si j'utilise la fonction « print0 » pour imprimer les valeurs, c'est la sortie:

AA 
AT 
[None, None] 

Je veux savoir pourquoi vient ici deux valeurs 'None', puisque ces deux valeurs ne viennent pas quand j'utilise la méthode 1? Je veux faire la boucle for en utilisant la technique de parallélisation, mais avec la valeur 'None', la fonction delayed du paquet joblib ne peut pas fonctionner. Merci. Mise à jour: si je veux le faire en parallèle:

Parallel(n_jobs=2)(delayed(print0)(seq) for seq in seqs) 

Il donnera un message d'erreur:

TypeError: expected string or Unicode object, NoneType found 
+4

. .. Parce que vous ne renvoyez rien ... –

+1

les deux extraits sont sémantiquement différents: l'un est juste une boucle for-avec une instruction d'impression tandis que l'autre, vous créez une liste avec la compréhension de liste en utilisant une fonction qui ne renvoie rien (aucun –

+0

En plus de ce qui a été proposé dans les réponses, si vous ne voulez pas voir les 'None's, rejeter la valeur de l'expression:' _ = [print0 (s) for s in seqs] '. – DyZ

Répondre

0

None est la valeur de retour de print0(s). Lors de l'utilisation de l'impression, le résultat sera simplement affiché dans la sortie standard, mais pas retourné comme résultat de la fonction. Ainsi, la liste de compréhension évalue la fonction en tant que None. Votre funtion devrait plutôt être:

def print0(s): 
    return s 
3

La syntaxe [print0(s) for s in seqs] est un List Comprehension.

Il appellera print0(s) pour chaque élément de seq et affichera le résultat dans une liste. Parce que print0 ne renvoie rien, vous obtenez une liste de 2 None s.

6

Puisque vous utilisez l'interpréteur interactif, qui, par des impressions par défaut pour tout le repr() objet retourné au niveau supérieur, vous voyez une liste des objets None, ce qui est ce qui se est retourné des appels de votre fonction print0. C'est pourquoi ce n'est pas une bonne pratique de créer une liste juste pour ses effets secondaires, en plus du fait que tous ces objets sont stockés en mémoire (bien qu'il n'y ait qu'un seul objet None, et cette liste sera récupérée dès que vous renvoyez autre chose au niveau supérieur - jusque-là, il est stocké dans la variable spéciale _).

Vous reconnaîtrez comment l'interprète affiche le repr() de tout objet retourné au niveau supérieur:

>>> 'hello' 
'hello' 

Et il est logique que la liste littérale suivante apparaît:

>>> [print()] 

[None] 

Et le même pour une compréhension:

>>> [print(num) for num in range(3)] 
0 
1 
2 
[None, None, None] 

Mais c'est b etter pour utiliser une boucle ordinaire. Les doublures sont amusantes, mais pas toujours idéales.

>>> for num in range(3): 
...  print(num) 
... 
0 
1 
2 

Notez que vous pouvez obtenir des résultats bizarres si une fonction imprime une chose et retourne une autre:

>>> def f(): 
...  print(1) 
...  return 2 
... 
>>> [f() for num in range(3)] 
1 
1 
1 
[2, 2, 2] 
>>> for num in range(3): 
...  f() 
... 
1 
2 
1 
2 
1 
2 

Ceci est une démonstration de « effets secondaires ». Essayez d'éviter le code qui effectue des modifications dans deux endroits différents à la fois (dans ce cas, les résultats affichés de l'interpréteur interactif et les actions locales d'une fonction).

+1

Aucun n'est un singleton, comme vous l'avez dit, donc je ne comprends pas ce que vous voulez dire au sujet de la liste ou de l'empreinte mémoire. –

+1

C'est une bonne réponse à cause de sa profondeur, mais elle ne parvient pas à dissiper toute confusion de l'affiche. Je ne pense pas qu'ils s'intéressent à la collecte des ordures ou aux bonnes pratiques de liste. – byxor

+1

@CharlesAddis - Si elles utilisent une fonction qui renvoie des données non-singleton qui ne les intéressent pas, elles utilisent la mémoire O (n). C'est juste une autre raison d'écrire une boucle appropriée au lieu d'une compréhension quand vous ne vous souciez pas du résultat. – TigerhawkT3

0

Je vois des questions si souvent, il devrait y avoir une réponse ultime à tous, ce qui déclenche automatiquement chaque fois que print et None sont tous deux présents dans une seule question ...

Alors que la réponse à la question lui-même est trivial, ce que, je pense, vous devez vraiment comprendre est une différence entre un side effect et un valeur de retour. Par exemple:

a = 10 
def three(x): 
    global a 
    a += x #side effect 
    print x #side effect 
    return 3 #returning 

La valeur nos three() de retour de la fonction est 3. Il a également deux effets secondaires: la modification d'une variable globale a et l'impression. Ceux-ci sont appelés effets secondaires car ils modifient quelque chose en dehors de la fonction: la variable a et l'état de l'écran, respectivement.

Dans votre exemple:

def print0(s): 
    print s 

il n'y a pas de valeur de retour explicite, seul un effet secondaire (impression). En d'autres termes, il imprime quelque chose sur l'écran, puis ne renvoie rien. Ce rien est appelé None en Python. Si vous l'appelez comme ceci:

a = print0(3) 

il imprime 3 dans la console. Mais quelle est la valeur de a maintenant?

>>> print a 
None 

Maintenant à la compréhension de la liste. C'est un concept emprunté à la programmation fonctionnelle (Lisp, etc.) où il s'appelle map. Il y a encore la fonction map en Python, de sorte que les deux lignes suivantes sont équivalentes:

[print0(s) for s in seqs] 
map(print0, seqs) 

Ce qu'ils font tous les deux est de prendre les éléments de la liste d'entrée (seqs), un par un, en appliquant la fonction (print0) à chaque d'entre eux et de mettre les résultats (valeurs de retour), un par un, dans la liste de sortie, qu'ils reviennent. Chaque fois qu'ils appellent votre print0 fonction, il affiche son argument s sur l'écran (un effet secondaire) et ne renvoie rien (None), qui est mis dans la liste de sortie par la compréhension de la liste ou map. Si vous le faites dans la console interactive Python, ce résultat apparaît dans la sortie ([None, None]), sinon - il est toujours produit par l'interpréteur et immédiatement rejeté, sauf si vous le passez en argument à une autre instruction. Ce qui nous amène à votre dernière ligne de code et le message TypeError. Vous passez votre fonction à une autre fonction, qui attend une chaîne, elle ne se soucie pas des effets secondaires que votre fonction peut produire.Le contexte est pas tout à fait clair pour moi, mais vous devriez probablement définir votre fonction comme ceci:

def print0(s): 
    return str(s) 

Maintenant, au lieu d'imprimer s à l'écran, il convertit en string puis retours il. Notez que si vous les appelez à l'intérieur de l'interpréteur interactif tout comme print0(s), il semble qu'ils produisent le même effet, ce qui peut être déroutant. Cependant, si vous faites a = print0(s), vous verrez que a est différent. Dans certaines langues, la dernière valeur calculée devient automatiquement la valeur de retour, mais avec Python qui est pas le cas pour les fonctions régulières:

def times_three(x): 
    x*3 

retours None. Cependant, il y a aussi lambda-fonctions, pour lesquelles cette est le cas:

times_three = lambda x: x*3 
times_three(5) #returns 15 
0

Une autre façon, si vous voulez le faire de manière interactive dans une seule ligne est d'utiliser .join

text = ['28', '43', '6f', '72', '65', '20', '64', '6f', '6d', '70', '65', '64', '29', '0a'] 

''.join(chr(int(x, 16)) for x in text)