2012-11-14 1 views
3

Je suis un programmeur très novice. J'essaie d'utiliser l'outil combinations dans le module itertools. Alors je tente:Python: la méthode appelante renvoie <[objet] à [pointeur]> au lieu de l'objet

from itertools import * 
print combinations('12345', 3) 

mais au lieu de l'('123', '124', '125', [...]) attendu que je reçois <itertools.combinations object at [pointer]>. Je suis très confus parce que l'appel de méthodes dans d'autres modules renvoie le résultat attendu, par exemple:

import random 
print random.randrange(10) 
>>> 9 

Qu'est-ce que je fais mal avec le module itertools?

Répondre

6

Rien. Le résultat est ce qu'il devrait être. Ce que vous ne parlez apparemment pas, c'est que le résultat est un itérateur, pas une liste/un tuple de résultats entièrement évalués. La sortie que vous voyez est le repr() de cet objet (pas renvoyant une chaîne). Vous pouvez convertir le premier dans le second en passant au constructeur list:

import itertools 
print list(itertools.combinations('12345', 3)) 

Mais quand vous n'avez pas besoin que vous simplement itérer sur les valeurs, il permet d'économiser beaucoup de mémoire en ne stockant pas tous les résultats en même temps. Cela permet également d'éviter le travail en ne consommant pas tout l'itérateur (par exemple, en trouvant la première combinaison satisfaisant certaines conditions puis retournant).

3

itertools.combinations renvoie un itérable (vous pouvez voir l'utilisation du mot-clé yield dans le document equivalent codes donné dans le document Python). Vous pouvez utiliser list(combinations(...)) si vous voulez imprimer la séquence complète.

>>> print list(combinations('12345', 3)) 
[('1', '2', '3'), ('1', '2', '4'), ('1', '2', '5'), ('1', '3', '4'), ('1', '3', '5' ('2', '3', '5'), ('2', '4', '5'), ('3', '4', '5')] 
+1

Techniquement, pas un générateur, juste un itérable (d'une classe manuscrite). Mais oui, cela pourrait aussi bien être mis en œuvre en tant que générateur. – delnan

+0

[OP] Merci, je me suis débrouillé seul quelques minutes après avoir posé la question. Je n'ai pas réalisé que 'combinations' renvoie un itérateur par opposition à la liste actuelle. J'ai également compris que l'appel 'list()' sur un itérateur retournera une liste réelle. Merci!! – jayhendren

+0

@delnan: merci, j'ai corrigé mon message – Nicolas

0

itertools.combination est une classe; en tant que tel, appelant itertools.combinations() renvoie une instance de cette classe par exemple, qui peut être itéré pour obtenir les valeurs:

for combo in combinations('12345', 3): 
    print combo 
+0

Merci! Je ne connais pas beaucoup la programmation orientée objet, donc je ne suis pas encore clair sur le comportement des instances de classes. – jayhendren

2

C'est un itérateur. Vous pouvez le convertir en list ou tuple en utilisant list(combinations('12345', 3)) ou tuple(combinations('12345', 3)).

Par votre question je pense vous pouvez avoir une certaine confusion sur ce que sont les séquences, itérations et itérateurs. Je pense qu'il est utile de les comprendre pour pouvoir écrire et/ou comprendre le code python, donc je vais essayer de vous donner une explication à ce sujet.

Les objets list et tuple sont séquences. Les séquences sont des objets qui prennent en charge certaines opérations spécifiques. A savoir qu'ils sont iterables (vous pouvez le faire for elem in sequence), ils soutiennent « l'accès de l'élément » (sequence[key] est valide) ils ont une « longueur » (len(sequence) est valide) et vous pouvez vérifier si un article est dans la séquence (elem in sequence est valide). [Il existe un complete list d'opérations qui constitue le "protocole de séquence". Hélas c'est spécifique pour le C-API. Néanmoins, les noms et les explications de ces fonctions devraient vous donner une idée de l'ensemble des opérations qu'ils soutiennent]

En python, il y a deux autres types d'objets qui, dans certains cas, peut être utilisé à la place de séquences: iterables et itérateurs.

Un itérable est un objet qui prend en charge l'itération. En parlant de python, un objet est itérable s'il a une méthode __iter__ qui retourne un itérateur.

Un itérateur est un objet qui itère une fois sur une itérable et donne les valeurs une par une. En python, un itérateur est un objet qui implémente les méthodes __iter__ et __next__ (next dans python2). __iter__habituellement "ne fait rien", renvoie simplement l'objet lui-même. La méthode next renvoie la valeur suivante dans le itérable.

Maintenant, combinations('12345', 3) est un itératives, ce qui signifie que vous pouvez passer en boucle, mais vous ne pouvez pas accéder à ses éléments en utilisant la syntaxe iterable[key] et vous ne pouvez pas obtenir sa longueur avec len. Pourquoi utiliseriez-vous des itérateurs? Dans certaines situations, vous pouvez éviter d'avoir toute une séquence de valeurs en mémoire pour l'itérer. Par exemple, si vous souhaitez effectuer une boucle sur les numéros 1 à 100, vous ne devez pas créer un list de longueur 100 rempli avec les numéros et parcourir par-dessus. Donnez une valeur que vous pouvez calculer en ajoutant 1. Donc, fondamentalement, les iterables sont un moyen de réduire l'utilisation de la mémoire, et en général sont une abstraction de la fonctionnalité nécessaire pour "boucler quelque chose". Si vous voulez une séquence, vous pouvez les convertir comme indiqué précédemment.

Les générateurs sont des générateurs d'un type particulier d'itérateurs. Les générateurs sont tout simplement itérateurs qui peuvent être écrits en utilisant la fonction syntaxe, en particulier, ils utilisent le mot-clé yield:

>>> def numbers(n): 
...  while n > 0: 
...    yield n 
...    n -= 1 
... 
>>> numbers(5) 
<generator object numbers at 0xb744a93c> 
>>> for elem in numbers(5): 
...  print elem 
... 
5 
4 
3 
2 
1 

Comme vous pouvez le voir lorsque vous appelez numbers le code est pas Execute. Au lieu de cela, python crée un objet générateur, qui est un itérateur. Lorsque vous parcourez l'objet, le code à l'intérieur de la fonction est exécuté jusqu'à ce que le yield soit rencontré. Lorsque cela se produit, l'argument "yield" est renvoyé et l'exécution est gelée. Quand une nouvelle itération commence, elle recommence.

Probablement vous pouvez mieux voir le flux d'exécution dans cet exemple:

>>> def flow(): 
...  yield 'Execution stopped here' 
...  yield 'Execution continues' 
...  yield 'Execution ended' 
... 
>>> generator = flow() 
>>> next(generator) #same as generator.__next__() 
'Execution stopped here' 
>>> next(generator) 
'Execution continues' 
>>> next(generator) 
'Execution ended' 
>>> next(generator) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 

Vous pourriez être intéressé par l'PEP255 où ils ont été proposés. En fait, ils ont été étendus pour fournir des fonctionnalités coroutines, mais je pense que cela suffit pour le moment.

Questions connexes