Comment un programme Python peut-il facilement être facilement Importer un module Python d'un fichier avec un nom arbitraire fort>? p>
Le mécanisme d'importation de bibliothèque standard ne semble pas aider. Une contrainte importante est que je ne veut pas un fichier de bytecode accompagnant fort> apparaître; Si j'utilise Le mécanisme d'importation Python s'attend à ce qu'il sait mieux ce que le nom de fichier sera: les fichiers de module sont trouvés dans des emplacements spécifiques de système de fichiers, et en particulier que les noms de fichiers ont des suffixes particuliers ( qui affronte avec une autre convention, au moins sur UNIX: les fichiers qui seront exécutés comme une commande doivent être nommé sans référence au langage de mise en œuvre . La commande de faire "FOO", par exemple, devrait être dans un fichier de programme nommé Test de l'unité Un tel fichier de programme nécessite toutefois d'importer ce fichier. J'ai besoin des objets du fichier de programme sous forme d'objet de module Python, prêt pour la manipulation dans les cas de test de l'unité, exactement comme Quel est le moyen pythonique imp.load_module code> sur un fichier source nommé foo code>, un fichier nommé fooc code> apparaît, qui est désordonné et déroutant. P>
foo.py code> pour la source Python code, etc.) et pas d'autres. p>
foo code> sans suffixe. P>
importer code> me donnerait. P>
.py code>, sans fichier de bytecode apparaissant < / fort> pour cette importation? p>
3 Réponses :
Ma meilleure implémentation jusqu'à présent est (à l'aide de fonctionnalités uniquement en python 2.6 ou ultérieur):
import os
import sys
import imp
import contextlib
@contextlib.contextmanager
def preserve_value(namespace, name):
""" A context manager to preserve, then restore, the specified binding.
:param namespace: The namespace object (e.g. a class or dict)
containing the name binding.
:param name: The name of the binding to be preserved.
:yield: None.
When the context manager is entered, the current value bound to
`name` in `namespace` is saved. When the context manager is
exited, the binding is re-established to the saved value.
"""
saved_value = getattr(namespace, name)
yield
setattr(namespace, name, saved_value)
def make_module_from_file(module_name, module_filepath):
""" Make a new module object from the source code in specified file.
:param module_name: The name of the resulting module object.
:param module_filepath: The filesystem path to open for
reading the module's Python source.
:return: The module object.
The Python import mechanism is not used. No cached bytecode
file is created, and no entry is placed in `sys.modules`.
"""
py_source_open_mode = 'U'
py_source_description = (".py", py_source_open_mode, imp.PY_SOURCE)
with open(module_filepath, py_source_open_mode) as module_file:
with preserve_value(sys, 'dont_write_bytecode'):
sys.dont_write_bytecode = True
module = imp.load_module(
module_name, module_file, module_filepath,
py_source_description)
return module
def import_program_as_module(program_filepath):
""" Import module from program file `program_filepath`.
:param program_filepath: The full filesystem path to the program.
This name will be used for both the source file to read, and
the resulting module name.
:return: The module object.
A program file has an arbitrary name; it is not suitable to
create a corresponding bytecode file alongside. So the creation
of bytecode is suppressed during the import.
The module object will also be added to `sys.modules`.
"""
module_name = os.path.basename(program_filepath)
module = make_module_from_file(module_name, program_filename)
sys.modules[module_name] = module
return module
Utilisez des bibliothèques standard, Luke!
WARVARIUC: Veuillez consulter la question des approches de la bibliothèque standard essayées et pourquoi elles ne répondent pas aux exigences.
import os
import imp
py_source_open_mode = "U"
py_source_description = (".py", py_source_open_mode, imp.PY_SOURCE)
module_filepath = "foo/bar/baz"
module_name = os.path.basename(module_filepath)
with open(module_filepath, py_source_open_mode) as module_file:
foo_module = imp.load_module(
module_name, module_file, module_filepath, py_source_description)
Cela a l'inconvénient que le module est compilé dans un fichier bytecode, qui apparaîtra sur le disque (dans ce cas nommé foo / bar / bazc code>). Ce n'est pas ce qui est nécessaire.
J'ai couru dans ce problème et, après avoir omis de trouver une solution, j'ai vraiment aimé, résolu en faisant un lien sympathique avec une extension .py. Donc, le script exécutable peut être appelé Cela a l'avantage supplémentaire de faciliter la conservation des tests d'unité dans un répertoire différent de celui de l'exécutable. P> commande code>, la liaison symbolique qui pointe sur elle est command.py code> et les tests de l'unité sont dans command_test.py code>. Le Symlink est heureusement accepté lors de l'importation du fichier sous forme de module et le script exécutable suit des conventions de nommage standard. P>
Merci. De nombreux éditeurs de texte, cependant, créeront une copie temporaire copie i> du fichier, puis lorsque vous enregistrez, ils vont déplacer i> qui copient sur le nom d'origine - qui supprime ensuite le nom. Symlink et met un vrai fichier à sa place. Donc, cette approche a des avertissements aussi :-(
Il n'y a pas de problème nommer une commande i> sans l'extension ".py", donc vraiment il n'y a pas de choc avec la convention
Gnibbler: Je ne comprends pas votre commentaire. Cette question complète est fondée sur les problèmes observés. Votre réponse proposée ignore les contraintes énoncées dans la question.
Sur UNIX, vous ne voudriez généralement pas nommer le fichier Python qui doit être exécuté "foo" plutôt que
"foo.py". La première ligne de "foo" devrait être quelque chose comme code> #! / USR / bin / env python` Donc, la Shell sait utiliser Python pour exécuter le script lorsque vous tapez "./foo"Gnibbler: Oui, exactement. Nous sommes tous deux d'accord comment i> faire un tel fichier. Et puis vous obtenez les problèmes décrits dans la question. Je ne vois pas pourquoi nous avons cette discussion dans les commentaires, lorsque la question indique clairement ce que les problèmes sont avec l'approche que nous sommes tous deux d'accord.
Mon approche consistait à garder Foo.py dans le contrôle de la source avec les tests et à dénuder l'extension .PY dans l'étape "Faire installer".