Supposons que vous ayez du travail fastidieux à faire lorsqu'un module/classe est importé pour la première fois. Cette fonctionnalité dépend d'une variable passée. Cela ne doit être fait que lorsque le module/la classe est chargé. Toutes les instances de la classe peuvent ensuite utiliser le résultat.
Par exemple, j'utilise rpy2:
import rpy2.robjects as robjects
PATH_TO_R_SOURCE = ## I need to pass this
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time
class SomeClass:
def __init__(self, aCurve):
self._curve = aCurve
def processCurve(self):
robjects.r['someRFunc'](robjects.FloatVector(self._curve))
Suis-je obligé de créer une fonction de niveau module que j'appelle pour effectuer le travail?
import someClass
someClass.sourceRStuff(PATH_TO_R_SOURCE)
x = someClass.SomeClass([1,2,3,4])
etc...
Avoir une fonction de module init n'est pas inconnu. Pygame le fait pour les fonctions d’initialisation sdl. Alors oui, votre meilleur pari est probablement
import someModule
someModule.init(NECESSARY_DATA)
x = someModule.someClass(range(1, 5))
Je devais faire quelque chose de similaire pour mon projet. Si vous ne voulez pas vous fier au script d'appel pour exécuter la fonction d'initialisation, vous pouvez ajouter votre propre fonction intégrée Python, qui est ensuite disponible pour tous les modules au moment de l'exécution.
Veillez à nommer votre fonction intégrée en quelque chose d'unique qui risque peu d'entraîner une collision d'espace de noms (par exemple, myapp_myvarname
).
run.py
import __builtin__
__builtin__.myapp_PATH_TO_R_SOURCE = 'path.to.r.source'
import someClass
module oneClass .py
import rpy2.robjects as robjects
import __builtin__
if hasattr(__builtin__, "myapp_PATH_TO_R_SOURCE"):
PATH_TO_R_SOURCE = __builtin__.myapp_PATH_TO_R_SOURCE
else:
PATH_TO_R_SOURCE = ## Some default value or Null for Exception handling
robjects.r.source(PATH_TO_R_SOURCE, chdir = True)
...
Cela fonctionne bien pour les variables qui peuvent avoir une valeur par défaut mais que vous souhaitez autoriser le remplacement lors de l'importation. Si la variable __builtin__
n'est pas définie, il utilisera une valeur par défaut.
Edit: Certains considèrent cela comme un exemple de "correction de singe". Pour une solution plus élégante sans patch de singe, voir mon autre réponse .
S'il n'y a qu'un seul élément de configuration à définir, j'ai trouvé qu'il était correct de remplacer le __builtin__
de python, mais il s'agit d'un exemple de "Correction de singe" qui est mal vu par certains.
Une façon plus simple de le faire, ce qui est très utile pour plusieurs éléments de configuration de votre projet consiste à créer un module de configuration distinct qui est importé en premier par votre code d'habillage, puis les éléments définis à l'exécution, avant que votre module fonctionnel ne l'importe. Ce modèle est souvent utilisé dans d'autres projets.
myconfig/__ init__.py:
PATH_TO_R_SOURCE = '/default/R/source/path'
OTHER_CONFIG_ITEM = 'DEFAULT'
PI = 3.14
monmodule/__ init__.py:
import myconfig
PATH_TO_R_SOURCE = myconfig.PATH_TO_R_SOURCE
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time
class SomeClass:
def __init__(self, aCurve):
self._curve = aCurve
if myconfig.VERSION is not None:
version = myconfig.VERSION
else:
version = "UNDEFINED"
two_pi = myconfig.PI * 2
Et vous pouvez modifier le comportement de votre module au moment de l'exécution à partir du wrapper:
run.py:
import myconfig
myconfig.PATH_TO_R_SOURCE = 'actual/path/to/R/source'
myconfig.PI = 3.14159
# we can even add a new configuration item that isn't present in the original myconfig:
myconfig.VERSION="1.0"
import mymodule
print "Mymodule.two_pi = %r" % mymodule.two_pi
print "Mymodule.version is %s" % mymodule.version
Sortie:
> Mymodule.two_pi = 6.28318
> Mymodule.version is 1.0
Il n'y a aucun moyen de passer une variable à l'importation.
Quelques idées:
Quelques autres options pouvant atteindre votre objectif (bien qu'une fonction init () soit probablement plus propre):
Non, vous n'êtes pas coincé avec une fonction de niveau module, c'est probablement la meilleure option. Vous pouvez également utiliser les décorateurs intégrés staticmethod
ou classmethod
pour en faire une méthode sur someSclass
pouvant être appelée avant son instanciation.
Cela aurait du sens seulement si tout ce qui n’était pas someClass
était utilisable sans initialisation et je pense toujours qu’une fonction au niveau du module est préférable.
Il y a deux solutions auxquelles je peux penser, qui sont toutes les deux des solutions très simples. La première consiste à abandonner les importations et à exécuter votre script comme ceci
sys.argv[1] = "argument 1"
sys.argv[2] = "argument 2"
execfile("/path/to/dependency.py") #depreciated in python 3.x
La seconde consiste à placer vos arguments dans un fichier temporaire externe, puis à lire ce fichier dans la dépendance.
Pourriez-vous bénéficier d'un proxy qui implémente le chargement différé?
Consultez l'état actif " Recette du module importé ".