7
votes

Peut-on appeler l'étagère de Python.Open à une mode imbriquée?

J'essaie d'écrire une bibliothèque de mémoisation qui utilise Spinve pour stocker le Valeurs de retour de manière persistante. Si j'ai des fonctions mémorisées appelant d'autres fonctions mémorisées, je me demande comment ouvrir correctement le fichier de tablette.

$ python3 shelve_test.py
outside function
Traceback (most recent call last):
  File "shelve_test.py", line 33, in <module>
    other_expensive_calculation()
  File "shelve_test.py", line 13, in wrapper
    result = user_function(*args, **kwds)
  File "shelve_test.py", line 31, in other_expensive_calculation
    return expensive_calculation()
  File "shelve_test.py", line 9, in wrapper
    with shelve.open(filename, writeback=True) as cache:
  File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/shelve.py", line 239, in open
    return DbfilenameShelf(filename, flag, protocol, writeback)
  File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/shelve.py", line 223, in __init__
    Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback)
  File "/usr/local/Cellar/python3/3.4.1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/dbm/__init__.py", line 94, in open
    return mod.open(file, flag, mode)
_gdbm.error: [Errno 35] Resource temporarily unavailable


8 commentaires

Je pense que vous ne devriez pas avoir deux pointeurs d'écriture ouverts sur le même fichier. Cela conduira presque certainement à un comportement indésirable ... Utilisez plutôt fichier.seek (0) si vous souhaitez revenir à la Début d'un fichier ouvert


Ok, a du sens, mais je ne veux vraiment pas revenir au début des fichiers. Je veux fondamentalement le deuxième Ouvrir pour utiliser le fichier déjà ouvert du premier, s'il a déjà été ouvert, sinon l'ouvrir.


c'est évidemment toujours ouvert depuis que vous êtes toujours dans son bloc de contexte, sauf si vous la fermez explicitement quelque part


@ Saul.shaanabrook Il est difficile de vous dire comment vous devriez faire cela sans une meilleure idée de la manière dont votre bibliothèque est organisée. Les fonctions de mémoisation sont-elles de toutes les parties de la même classe?


@Dano j'ai mis à jour ma question avec un exemple spécifique. Est-ce que ça fait du sens?


@Dano mis à jour à nouveau, avec l'exemple de travail (sauf non)


Compte tenu de votre exemple mis à jour, la question réelle n'est pas " peut Ouvrir être appelée à une mode imbriquée ?", Mais plutôt, " peut shelve.open être appelé à une mode imbriquée ? ".


@ Robᵩ Merci pour la suggestion, terminée


3 Réponses :


-1
votes

Vous ouvrez deux fois le fichier mais ne la fermez jamais pour mettre à jour le fichier pour n'importe quelle utilisation. Utilisez f.close () à la fin.


1 commentaires

Vient de regarder ça. Vous ne mettez pas à jour à partir de la première partie, donc il n'y a nulle part pour le "là" pour y aller car il n'existe pas encore. C'est comme ouvrir deux fenêtres de celui-ci




2
votes

plutôt que d'essayer de nier les appels à ouvrir (qui, comme vous l'avez découvert, ne fonctionne pas), vous pouvez rendre votre décorateur à conserver une référence à la poignée renvoyée par shelve.open , puis si Il existe et est toujours ouvert, réutiliser que pour les appels ultérieurs: xxx

sortie: xxx

modifier:

Vous pouvez également implémenter le décorateur à l'aide d'un faiblesvalueddictionnaire , qui ressemble un peu plus lisible: xxx

dès qu'il n'y a pas d'autres références à une poignée, ce sera supprimé du dictionnaire. Étant donné que notre poignée ne dépasse que lorsque l'appel le plus externe à une fonction décorée se termine, nous aurons toujours une entrée dans la dicte pendant qu'une poignée est ouverte et qu'aucune entrée juste après sa fermeture.


9 commentaires

Ce n'est pas ce avec shelve.open (nom de fichier, rétablissement = true) comme c: fermez l'étagère après ce bloc? Dans ce cas, il ne sera pas ouvert la prochaine fois?


@ Saul.shaanabrook Oui, mais le décorateur vérifie cela. Avec le pas hasattr (getattr (cache, marque_name) .dict, "fermé") partie du si instruction. cache. .Dict aura un attribut fermé si la poignée est fermée. Si nous le trouvons, nous ouvrons à nouveau la poignée.


@ Saul.Shaanabrook Aussi, je viens de modifier ma réponse afin que le décorateur prend en charge l'utilisation des poignées de conservation pour plusieurs fichiers de cache. Et j'ai mis à jour la section de sortie pour refléter la sortie lorsque le cache n'existe pas déjà.


Je reçois une erreur lorsque j'exécute ce script: Gist.github.com/saulshanabrook/e5000eebeffde91C7453


YEP La version mise à jour fonctionne. Merci beaucoup! c'est parfait


J'ai créé une version mise à jour (je pense) est un peu plus simple gist.github.com/saulshanabrook/e62A5669FE6FB87220D6 < / a>


@ Saul.shaanabrook Il est plus simple, mais cela ne fonctionnera pas si vous apportez des appels imbriqués vers des méthodes décorées à l'aide de , mais avec des valeurs différentes pour FileName . Il ne fermez pas non plus l'étagère si une exception non capturée se produit dans user_function (c'est pourquoi vous utilisez avec ci-dessus.open (...) en premier lieu).


Pouvez-vous commenter la sécurité de votre exemple de votre exemple? C'est à dire. Sera-t-il sauvegarder avoir des fonctions décorées appelées à partir de plusieurs threads? Utiliseront-ils alors le même manche? Et cela sera-t-il sauvegarder?


@Martinito Ce n'est pas un fil-sûr comme écrit. étagère ne prend pas en charge l'accès simultané de lecture / écriture à Splasved Les objets (bien que des lectures simultanées sont correctes). Donc, vous auriez besoin de protéger l'accès à l'étagère avec un mutex pour vous assurer qu'un seul thread l'utilise à la fois.