J'ai besoin de boucle jusqu'à ce que je frappe la fin d'un objet semblable à un fichier, mais je ne trouve pas de "manière évidente de le faire", ce qui me fait suspecter que je suis négligeant quelque chose, bien, évident. : -)
J'ai un ruisseau (dans ce cas, c'est un objet Stringio, mais je suis curieux du cas général) qui stocke un nombre inconnu d'enregistrements dans le format "len_name = data.read(4)
while len_name != "":
len_name = struct.unpack("<I", len_name)[0]
names.append(data.read(len_name))
len_name = data.read(4)
6 Réponses :
Avez-vous vu comment itération des lignes sur des lignes dans un fichier texte? Vous pouvez faire la même chose avec votre propre générateur: P> def read_blocks(file_obj, size):
while True:
data = file_obj.read(size)
if not data:
break
yield data
for block in read_blocks(file_obj, 4):
use(block)
Vous pouvez également structurer votre boucle comme une boucle tandis que dans le générateur. Utilisez ce qui est le plus lisible.
Je vois, comme prévu, que la réponse typique et la plus populaire utilise des générateurs très spécialisés pour "lire 4 octets à la fois". Parfois, la généralité n'est pas plus difficile (et beaucoup plus enrichissante ;-), donc, j'ai suggéré la solution très générale suivante: maintenant votre en-tête de boucle désirée est juste: Couteau d'armée suisse de boucle, ou, assez équivalent: p> pour len_name dans Funlooper (Data.Lead, 4): Code>. P>
porté code> idiome depuis Un commentaire a accusé ma version précédente légèrement moins générale (à la recherche du test de sortie en tant que
si pas de données: code>) d'avoir "une dépendance cachée", de toutes choses! -) p>
ITERTOOLS code>
, c'est bien aussi , bien sûr, comme d'habitude: p>
Bien qu'il y ait une dépendance cachée, car Funlooper nécessite la fonction de renvoyer un résultat non vrai pour indiquer la fin.
@ R.Pate, vous pouvez bien sûr ajouter trivialement à Funlooper A WearedOne code> argument de prédicat par défaut sur
_ code> et modifier le
si code> sur
Si cheedone (données): pause code> - Je ne pensais tout simplement pas que cela valait la peine de généraliser davantage la réponse avec ce code trivial lorsque j'étais sûr (et correct dans cela ;-) que les autres réponses seraient bien excivré spécialisé (sans bénéfice). Ah bien, puisque la spécialisation excessive gagne la journée de toute façon, laissez-moi éditer la réponse pour montrer que la généralité n'est pas plus difficile (et beaucoup plus enrichissante) dans ce cas ;-).
Je pense que vous m'interprimez mal interprété dans la mauvaise direction: Imho, le funlooper d'origine était aussi i> général. Étant donné que nous en dépendons déjà de la valeur de retour ayant une forme spécifique, il est raisonnable de dépendre ici de cette partie de l'interface type de fichier (la méthode de lecture), au lieu d'essayer de passer un appelé générique. À défaut, l'utilisateur doit au moins être au courant de la dépendance.
"Boolean False" n'est pas "un formulaire spécifique" - c'est un très général que beaucoup de types d'objets Python peuvent satisfaire. Une de vos deux réponses à cette question (!), La non acceptée qui est actuellement plus upéte, a exactement la même longueur et la même structure générale que mon originale (par normale si étiquette, i ne B> Postez de nombreuses réponses à une question!), alors rien n'est gagné de sa spécialisation extrême. (L'autre de vous réponde, la personne acceptée avec ITER et SENTINEL, est plus concise - pas aussi générale que la mine w / itertools, mais plus simple).
Si vous n'êtes pas d'accord pour dire que cela dépend d'une forme spécifique de valeur de retour, pourquoi avez-vous changé la réponse? Quelle autre manière avez-vous vu une dépendance? (J'ai mieux aimé votre réponse à l'origine.)
J'ai changé la réponse pour le faire, essentiellement "universel", plutôt que juste i> "très général". Si le choix clair et évident de «vrai ou faux» doit être critiqué comme une «dépendance cachée» (l'un des défauts les plus horribles et les plus horribles, un composant logiciel pourrait éventuellement avoir!), Il est donc clairement nécessaire de se frotter dans les critiques » Faites face à la supériorité technique évidente de cette solution - en faisant évident l'équivalence (précédemment impliquée) à (par exemple) filtre code> (qui prend un
Aucun code> pour signifier "vrai ou faux, comme évident ", ou sinon un prédicat).
Cette comparaison avec le filtre est à peu près exactement mon point: le filtre a une valeur explicite qui indique ce comportement, au lieu d'être implicite et, donc, cachée. Merci d'avoir clarifié pourquoi vous l'avez changé, nous devrons simplement accepter d'être en désaccord.
J'imagine. Un Aucun code> pour signifier "Utilisez la défaillance évidente ici" est une API Goofy en effet, très python 1,5 ou plus tôt; Beaucoup mieux, lorsque la réalisabilité est réalisable, c'est que la défaillance évidente soit silencieuse et la rendre explicite en cas de besoin via un argument nommé (par exemple, la touche
= code> argument facultatif à TRI & C, tous les arguments optionnels à < Code> Imprimer Code> dans PY3, & C).
Le marqueur EOF de Python est une chaîne vide Alors ce que vous avez est assez proche du meilleur que vous allez obtenir sans écrire une fonction pour enrouler dans un itérateur. Je pourrais être écrit de manière un peu plus pythonique en modifiant le pendant code> comme:
Cela nécessite dupliquer l'affectation à Len_Name avant la boucle (que vous avez laissée de côté) et il est presque toujours souhaité d'éviter cette duplication.
Je préfère la solution itératrice déjà mentionnée pour transformer cela en une boucle pour la boucle. Une autre solution écrite directement est la "boucle-and demi" de Knut que vous pouvez voir par comparaison comment cela est facilement hissé dans son propre générateur et utilisé comme une boucle. P > p>
Dans ce cas particulier, je pense que j'aime mieux la solution code> code> mieux, mais je me sens assez stupide de ne pas avoir pensé cela. Un bien mérité +1 pour vous. ;-)
Wow. Oui, cette solution iter () est belle. Combiné à une "Lambda:" et en fonction des fermetures le rend un peu plus difficile à comprendre, mais doux non-moins.
Vous pouvez combiner itération via iTER () avec une sentinelle:
for block in iter(lambda: file_obj.read(4), ""): use(block)
Certainement la meilleure réponse. Tu m'as eu sur celui-ci, j'oublie cette sentinelle si utile.
Je pense que j'aime ça le mieux aussi; Ce que ça fait est très clair parce qu'il y a si peu de code. Merci pour l'aide!
Juste un rappel pour être gentil et rembobiner le fichier si vous y avez écrit, avant itération dessus, c'est-à-dire File_Obj.seek (0).
J'irais avec la suggestion de Tendayi Re fonctionnaire et itérateur pour la lisibilité:
def read4(): len_name = data.read(4) if len_name: len_name = struct.unpack("<I", len_name)[0] return data.read(len_name) else: raise StopIteration for d in iter(read4, ''): names.append(d)
Aucune raison, juste quelque chose que je me suis rassemblé rapidement. J'ai modifié l'extrait.
Tant de réponses! Peut-être que je n'aurais pas dû passer juste avant d'aller déjeuner. :-)