2010-06-05 4 views
3

J'utilise un module faisant partie d'une API logicielle commerciale. La bonne nouvelle, c'est qu'il existe un module python - la mauvaise nouvelle est que c'est plutôt pythonien.Une façon plus pythonique d'itérer

itérer sur les lignes, la syntaxe follwoing est utilisée:

cursor = gp.getcursor(table) 
row = cursor.next() 
while row: 
    #do something with row 
    row = cursor.next() 

Quelle est la façon la plus pythonique pour faire face à cette situation? Je l'ai envisagé de créer une première fonction classe/générateur et enveloppant appels à une boucle en elle:

def cursor_iterator(cursor): 
    row = cursor.next() 
    while row: 
     yield row 
     row = cursor.next() 

[...] 

cursor = gp.getcursor(table) 
for row in cursor_iterator(cursor): 
    # do something with row 

Ceci est une amélioration, mais se sent un peu maladroit. Y a-t-il une approche plus pythonique? Dois-je créer une classe wrapper autour du type table?

+0

Mmmh 'cursor.next()' ressemble à vous * pourrait * être capable de faire 'pour row in cursor:' –

+1

@Fix, non. 'next' ne déclenche pas de [' StopIteration'] (http://docs.python.org/library/exceptions.html#exceptions.StopIteration), donc après les données réelles, ce serait juste en boucle avec 'row' être 'None'. –

+0

@Felix King: Presque, mais parce qu'un itérateur signale une terminaison en augmentant StopIteration, 'pour row in cursor:' va parcourir les lignes, puis donner un flux infini de 'None's. –

Répondre

11

En supposant que l'un des suivant et à côté est une faute de frappe et ils sont tous les deux la même chose, vous pouvez utiliser la variante pas si bien connu de la fonction iter intégré:

for row in iter(cursor.next, None): 
    <do something> 
+0

Bonne réponse! Oui, les fonctions sont les mêmes (pire encore, ils sont en quelque sorte insensible à la casse!). – fmark

+0

assez élégant! – pygabriel

1

Le meilleur moyen est d'utiliser une interface iterator Python autour de l'objet table, IMHO:

class Table(object): 
    def __init__(self, table): 
     self.table = table 

    def rows(self): 
     cursor = gp.get_cursor(self.table) 
     row = cursor.Next() 
     while row: 
      yield row 
      row = cursor.next() 

maintenant, vous appelez simplement:

my_table = Table(t) 
for row in my_table.rows(): 
    # do stuff with row 

C'est très lisible, à mon avis.

2

Vous pouvez créer un emballage personnalisé comme:

class Table(object): 
    def __init__(self, gp, table): 
     self.gp = gp 
     self.table = table 
     self.cursor = None 

    def __iter__(self): 
     self.cursor = self.gp.getcursor(self.table) 
     return self 

    def next(self): 
     n = self.cursor.next() 
     if not n: 
      raise StopIteration() 
     return n 

puis:

for row in Table(gp, table) 

Voir aussi: Iterator Types

+0

J'aime cette approche aussi. Je pourrais envisager d'entourer 'gp' de cette manière si j'ai besoin d'envelopper plus que l'itération du curseur. – fmark

Questions connexes