Perdu important.py fichier (écrasé en tant que Fichier 0byte), mais l'ancienne version toujours chargée dans IPYTHON en tant que module-peut - elle être récupérée?
En raison de ma stupidité, tout en gérant plusieurs sessions d'écran différentes avec vim ouvert dans beaucoup d'entre eux, en essayant d ' "organiser" mes sessions, j'ai réussi à écraser un script .PY très important avec un fichier 0Byte.
Cependant, j'ai une instance ipython ouverte qui, lors de l'exécution de ce même fichier .py en tant que module, se souvient toujours du code qui était là!
Je viens donc d'apprendre une dure leçon sur les sauvegardes (ma dernière a été faite par vim il y a environ une semaine, ce qui me laisserait beaucoup de travail à faire), ou Existe-t-il un moyen possible et concevable de récupérer le fichier .py à partir d'un module déjà chargé? je le mérite probablement pour être si cavalier, mais je suis sérieusement désespéré ici.
3 réponses
Comme indiqué dans les commentaires, inspect.getsource
ne fonctionnera pas, car cela dépend du fichier d'origine (c'est à dire, module.__file__
).
Meilleure option: vérifiez s'il y a un fichier .pyc
(ex, foo.pyc
devrait être à côté de foo.py
). Si c'est le cas, vous pouvez utiliser décompiler Python 2.7 .pyc pour le décompiler.
Les modules inspect
mettent également en cache la source. Vous pouvez avoir de la chance et utiliser inspect.getsource(module)
, ou inspect.getsourcelines(module.function)
s'il a été appelé dans le passé.
Sinon, vous devrez reconstruire le module "manuellement" en inspection des exportations (ie, module.__globals__
). Constantes et autres joyeusetés sont évidentes, et pour les fonctions que vous pouvez utiliser func.func_name
pour obtenir son nom, func.__doc__
pour obtenir la docstring, inspect.getargspec(func)
pour obtenir les arguments, et func.func_code
pour obtenir des détails sur le code: co_firstlineno
obtiendrez le numéro de la ligne, puis co_code
obtiendrez le code. Il y a plus sur la décompilation ici: Explorer et décompiler le bytecode python
Par exemple, Pour utiliser uncompyle2
:
>>> def foo():
... print "Hello, world!"
...
>>> from StringIO import StringIO
>>> import uncompyle2
>>> out = StringIO()
>>> uncompyle2.uncompyle("2.7", foo.func_code, out=out)
>>> print out.getvalue()
print 'Hello, world!'
Mais, Non-Je ne suis pas au courant de plus simple méthode pour prendre un module et récupérer le code source.
Avec le processus toujours en cours d'exécution, vous pouvez consulter votre espace de noms pour trouver des candidats à restaurer:
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'readline', 'rlcompleter', 'test']
Jetons un coup d'oeil à ce que nous avons en réserve pour test
:
>>> help(test)
Help on module test:
NAME
test
FILE
/Users/tfisher/code/ffi4wd/test.py
FUNCTIONS
call_cat(cat)
DATA
cat_name = 'commander sprinkles'
Qui a une sortie plus propre que de regarder les locaux à l'intérieur de test
:
>>> dir(test)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'call_cat', 'cat_name', 'json']
En utilisant le module inspect , nous pouvons obtenir les spécifications d'argument pour les fonctions:
>>> inspect.getargspec(test.call_cat)
ArgSpec(args=['cat'], varargs=None, keywords=None, defaults=None)
, Ou les lignes à l'intérieur de nos fonctions:
>>> inspect.getsourcelines(test.call_cat)
(['def call_cat(cat):\n', ' print("Hello %s" % cat)\n'], 5)
Qui est raisonnablement proche de la original:
import json
cat_name = 'commander sprinkles'
def call_cat(cat):
print("Hello %s" % cat)
Qui devrait fonctionner si le fichier est supprimé après avoir été importé et n'a pas été remplacé par un fichier du même nom plus récent (getsourcelines
utilise le cache d'objets si possible):
$ python -V
Python 2.7.10
$ ls | grep test
$
Vous devriez pouvoir utiliser inspect
Importez inspect
dans votre session Ipython, et, en supposant que vous essayez de récupérer myModule
, Faites:
q = inspect.getsource(myModule)
Et écrire q
dans un fichier.
[modifier] Cela a fonctionné pour moi en simulant le problème en utilisant Python 2.7.6, IPython 1.2.1
[Modifier #2]