9
votes

Comment charger paresseux une structure de données (Python)

J'ai un moyen de construire une structure de données (hors du contenu de fichier, disons):

class lazyload:
    def __init__(self,FILE):
        self.FILE = FILE
    def __getattr__(self,name):
        self = loadfile(self.FILE) # this never gets called again
                                   # since self is no longer a
                                   # lazyload instance
        return object.__getattribute__(self, name)


5 commentaires

Vous voudrez peut-être proxy __ non zéro __ et d'autres méthodes également.


@ephemient: il ressemble à un appel à __ non nulo __ passera par __ getattr __ , alors quel est le problème?


Je suppose que c'est un peu mieux de dire si self.f n'est pas Aucun plutôt que si non auto.f depuis loaderfile (fichier) < I> pourrait 0 ou la chaîne vide.


Hein, je pensais que ça ne l'a pas fait. Eh bien, peut-être que vous ne le faites pas.


Mise à jour de ma réponse, reflétant votre commentaire.


6 Réponses :


6
votes

Le module CSV dans le STDLibrary Python ne chargera pas les données tant que vous ne commencerez pas l'itération dessus, il est donc en fait paresseux.

Edit: Si vous devez lire via l'ensemble du fichier pour construire le DataStructure, avoir un Objet de chargement paresseux complexe que les objets de proxie sont surchargés. Il suffit de faire ceci: p> xxx pré>

avec la classe ci-dessus, vous pouvez le faire: p> xxx pré>

aussi p>

allkitties = kitties.get_data() # wait
print len(allkitties)
print kitties[32]


5 commentaires

Je ne traite pas réellement de fichiers csv ; C'était juste à des fins d'illustration. Mais c'est bon à savoir. De plus, loadfile devra itérer sur les données s'il s'agit de créer une structure de données non standard intéressante, de sorte que la paresse de csv peut ne pas suffire.


Si je comprends bien, votre self._data est exactement analogue à mon auto.f et votre _build_data est exactement analogue à mon Loadfile . La bonne chose à propos de l'utilisation __ getattr __ est que vous n'avez pas à écrire .get_data () partout; Vous pouvez interagir avec le wrapper exactement comme vous le feriez avec la structure de données directement.


Ouais, mais alors vous avez besoin de plus que __ getattr __ , vraiment, vous devez écrire un proxy complet, et cela ne vaut pas la peine. Simple = bon. Et vous n'avez pas à écrire Get_Data () partout. Vous venez d'écrire des données = thewrapper.get_data (), vous ne l'écrivez donc qu'une seule fois pour chaque fonction où vous devez accéder aux données.


N'écrireait pas data = thewrapper.get_data () vaincre le but du chargement paresseux? Pourquoi __ getattr __ pas assez en principe?


Non, cela ne vaincrait pas le but. Il chargerait les données, alors appellerait GetTATTR . Dans les deux cas, toutes les données sont chargées la première fois que vous le souhaitez.



1
votes

ne serait pas si non autonome code> mène à un autre appel à __ getattr __ code>, vous mettant une boucle infinie? Je pense que votre approche a du sens, mais d'être du côté sûr, je ferais cette ligne dans:

if name == "F" and not self.F:


2 commentaires

__ getattr __ est seulement appelé si la méthode n'est pas trouvée ( docs.python.org/py3k/reference/... ), donc je ne pense pas que ce soit un problème.


@Anton: Merci, je ne savais pas cela auparavant. Je laisserai cette réponse afin que d'autres personnes puissent voir cette information.



0
votes

Voici un piratage qui rend le travail de solution «encore meilleur», mais je pense que c'est assez ennuyant qu'il est probablement préférable d'utiliser la première solution. L'idée est d'exécuter l'étape self = loaderfile (self.file) code> en passant le nom de la variable en tant qu'attribut: xxx pré>

alors vous pouvez faire P >

kitties = lazyload("kitties.csv","kitties")
   ^                                 ^
    \                               /
     These two better match exactly


1 commentaires

Je sais que vous venez probablement de jeter des idées, mais ce genre de chose devrait vraiment être découragé. En plus de la méchanceté que vous avez signalé vous-même, cela ne fonctionnera que tant que l'objet doit seulement être mentionné par un seul nom global. Attribuez-le à un autre nom et travaillez à ce sujet, et les chatons sont rechargées et remplacées après chaque accès d'attribut. Passez-le à une fonction et chaque utilisation de l'objet dans la fonction le fera de recharger.



0
votes

Si vous avez besoin d'une utilisation chiots [32] Vous devez également définir __ getItem __ méthode car __ getattr __ ne pas attraper ce comportement.

Je mettant en œuvre la charge paresseuse pour mes besoins, il existe un code non adapté: xxx

(maître est un objet de registre qui charge des données lorsque je exécute sa méthode get () >

Cette implémentation fonctionne bien pour Isinstance () et Str () et JSON.Dumps () avec IT


1 commentaires

Pour autant que je sache, cette affirmation est incorrecte: "Si vous avez besoin d'utiliser chiots [32] Vous devez également définir __ getItem __ car __ getattr __ < / Code> Ne pas attraper ce comportement. " J'ai réellement testé le code dans la question et c'est fait travail. Cependant, il est vrai que __ getattribute __ n'atteigne pas __ getItem __ .



2
votes

Si vous êtes vraiment inquiet à propos de la déclaration IF, vous avez un objet STRAND> STARTFIVE STRAND>.

class LoadMe( object ):
   def __init__( self, parent ):
       self.parent= parent
   def load( self ):
       ## Actually load, setting self.parent.data
       return DoneLoading( self.parent )

class DoneLoading( object ):
   def __init__( self, parent ):
       self.parent= parent
   def load( self ):
       return self


12 commentaires

Je ne comprends pas cette réponse (encore?). Il semble que, une fois que l'objet est effectivement chargé, les seules méthodes disponibles sont obtenez et mettre . Mais il y a beaucoup d'autres moyens de pouvoir interagir avec la structure de données. Par exemple, chiots [34] et len (chiots) serait chacun lancer un attributeError à l'aide de cette méthode, non?


@Anton Geraschenko: "Mais il y a beaucoup d'autres moyens de pouvoir interagir avec la structure de données". Bon. Écrire plus de méthodes. Je ne pouvais que penser à deux. Vous pouvez penser à plus. Écrire plus.


Merci de clarifier. Maintenant, je comprends la réponse, mais c'est strictement pire que la solution que j'ai proposée dans la question, qui fait chaque méthode disponible pour une structure de données imaginable . __ getattr __ est une méthode de capture qui fait de longues listes de définitions de méthodes presque identiques inutiles.


@Anton Geraschenko: "Mais c'est strictement pire que la solution que j'ai proposée". Êtes-vous incapable de fusionner les deux? Je penserais que vous pouvez utiliser un conception Etat pour éliminer la déclaration IF, couplée à votre __ getattr __ -Based. Je suis tout à fait sûr que les réponses ne sont pas des propositions de toutes ou de rien, mais plus comme des suggestions ou des allusions.


Ah, je pense que je comprends mieux maintenant, même si je ne comprends toujours pas pourquoi vous voulez éliminer le si . Je suppose que c'est juste au cas où la structure de données est Aucun ou pour enregistrer l'heure de test si quelque chose est Aucun (?). La raison pour laquelle je pensais que le code (ne fonctionne pas) dans la question serait "encore meilleur", c'est qu'après chargé de la structure de données, l'objet serait complètement indiscernable d'un objet chargé directement, en bas au point que ce ne serait plus une instance de la classe wrapper.


@Anton Geraschenko: Cet objet serait complètement indiscernable. La classe "Wrapper" est l'objet correspondant. Pas de changement. La seule chose qui change est un état interne invisible à l'API.


L'objet serait en grande partie indiscernable, mais pas complètement. Le wrapper est une instance de luisyload , mais si elle est chargée directement, ce serait une instance de dict (ou autre). Le wrapper a source et attributs , que la structure de données ne le fait pas. Ceci est normalement hors de propos, mais note dans le Solution que j'ai donnée , après que l'enveloppe soit appelée une fois, il cesse être un wrapper . Il devient la structure de données directement, de la même manière que votre document arrête d'être un loadme et devient un DonLoading .


Bien sûr, cette solution me demande également de transmettre le nom de la variable comme un argument et suppose implicitement qu'il est global. Il serait plus agréable s'il y avait un moyen de réaffecter directement auto dans une méthode.


@Anton Geraschenko: "Nécessite que je passe le nom de la variable comme argument"? Comment __ getattr __ nécessite-t-il? Je pensais que __ getattr __ a donné accès aux variables sans utiliser le nom comme argument à une méthode. Qu'est-ce que je rate?


@Anton Geraschenko: "L'emballage est une instance de lazyload, mais si elle est chargée directement, ce serait une instance de dict (ou autre)." Faux et faux. Tout d'abord, LAZYLOID peut être une sous-classe de dict . Deuxièmement, une "charge directe" n'a pas de sens. Une fois que vous avez un chargeur paresseux, vous n'utiliseriez jamais rien d'autre. De plus, si vous voulez que votre "loader paresseux" soit l'objet d'application, c'est trivial. Le chargement paresseux n'est qu'une caractéristique de l'objet d'application. Puisque vous avez fourni zéro orientation sur ce que vous voulez cela d'autre, je ne peux pas prévoir toutes les fonctionnalités de l'application que vous souhaitez. Ajoutez-les vous-même s'il vous plaît.


Il semble que nous ayons de graves difficultés à communiquer. Je ne vois pas à vous ou que vous ne voyez pas pourquoi personne voudrait une classe de chargeuse paresseuse que l'agnostique sur quelle structure de données il chargée et est complètement fidèle (en ce sens qu'elle se comporte exactement comme la structure de données qu'elle charge de chargement, Mais a aucune caractéristique de son propre ). Désolé de gaspiller votre temps (et mon) temps.


@Anton Geraschenko: "Agnostic sur quelle structure de données il est en cours de chargement" est absurde. Vous ne pouvez pas être «agnostique» sur la classe chargée. Sauf si vous avez quelque chose d'autre à l'esprit que vous ne mettez pas dans la question. Mettez à jour la question pour contenir tout de vos besoins.



1
votes

Voici une solution qui utilise un décorateur de classe pour différer l'initialisation jusqu'à la première utilisation d'un objet:

kittens is instance of FileLoader: True
Performing expensive load operation
2
Felix
Eeek
kitties.csv
kitties.csv


0 commentaires