Condition sur les imports / python
RésoluBonjour,
Je viens vers vous car j'ai du mal pour trouver la meilleure optimisation de mes algorithmes.
Je m'explique : j'ai un fichier nommé
gen.py
qui s'exécute en important des paramètres, des informations supplémentaires, comme par exemple des URL, des clés d'API, etc. Ces paramètres, sont situés dans un fichier appelé :
param.py
Cependant, j'ai plusieurs fichiers de paramètres, param_1.py, param_2.py, param_3.py, etc.
Donc, l'idée que j'ai eu est de passer en argument à gen.py des numéros tels que 1,2,3 etc. en fonction du fichier de paramètre que je veux prendre en compte. Ainsi, à l'intérieur du script gen.py, j'écris une condition sur cet argument, pour importer le bon fichier de paramètre.
Seulement, voici le début de mon script :
from param import url, key, ssl, outputdir, fls, vadl try: from param import wdt except ImportError: wdt = False try: from param import lctgs except ImportError: lctgs = True try: from param import idl except ImportError: idl = False try: from param import eat except ImportError: eat = []
J'ai plusieurs fois l'import de param, donc il faudrait que chaque if englobe tout ce code, par exemple mon if serait du type :
if (sys.argv ==1): from param_1 import ...
Cela ne me semble pas très optimisé, je voulais donc savoir s'il y avait une meilleure solution ?
Je ne l'ai pas précisé, mais ensuite il y aura Crontab qui lancera un script (script.sh) qui lui lancera les commandes :
python3 gen.py 1 python3 gen.py 2 ...
Avec vérification des erreurs.
J'ai donc aussi penser à faire sur ce script (script.sh) une modification de noms des fichiers param, par exemple exécuter un par un le cas 1,2,3 etc. et à chaque fois faire :
mv param_1.py param.py python3 gen.py ...
Mais bon, ça ne me semble pas terrible
- Condition sur les imports / python
- Excel cellule couleur si condition texte - Guide
- Citizen code python avis - Accueil - Outils
- Excel condition ou - Guide
- Importer les favoris chrome - Guide
- \R python ✓ - Forum Python
2 réponses
Bonjour,
Il me paraît plus naturel d'avoir un seul fichier param.py qui expose une fonction load_params(i) et qui en fonction de i retourne le jeu de paramètres adéquat. Rien ne t'empêche ensuite de faire en sorte que load_param charge des informations depuis différents modules python en fonction de la valeur de i.
Ensuite, des paramètres sont comme leur nom l'indique... des paramètres. Donc quelque chose que l'utilisateur peut régler. Généralement, un utilisateur fournit les paramètres :
- de manière interactive :
- au travers d'une interface utilisateur (graphique ou texte), mettant en jeu éventuellement des fichiers tiers
- au lancement du programme :
- au travers d'un fichier de configuration (par exemple un fichier .ini ou .json)
- au travers des paramètres passés au programme en ligne de commande, mettant en jeu éventuellement des fichiers tiers
Dans ton cas, j'ai l'impression que ton programme doit simplement prendre en paramètre un fichier de configuration dans lequel sont définis les paramètres (URL, clés d'API, etc). Tu peux par exemple t'inspirer de cet exemple.
Bonne chance
Bonjour et merci pour ta réponse.
De ce que j'ai compris, j'aurais donc un seul fichier param.py avec à l'intérieur une fonction load_param(i) qui serait appelée dans un for (par exemple) qui traitera toutes les valeurs de i possibles.
Donc ensuite, gen.py importe ce module param.py, qui renvoie les différentes en fonction de i c'est cela ?
Pour mieux comprendre, le fichier param.py contient :
url = 'https://IP/' key = 'xxxx' outputdir = 'output' fs = {'pubd':'true'} id = False vadl = ['0', '1', '2', '3', '4', '5'] eat = [] wdt = False wlt = True
Et à savoir que chaque valeur peut changer en fonction des "i".
En fait, il vaut mieux que je modifie mon script gen.py, que je lui fasse prendre les 9 paramètres en arguments et que ces paramètres soient donnés par le script param.py qui traite tous les cas possibles, non ? Est-ce optimisé ?
Ok donc j'ai lu la deuxième partie de ton message, cela revient à ce que j'ai dit juste avant, sauf que tu dis que je peux directement donner le fichier contenant les paramètres en argument c'est cela ?
Oui c'est ça.
params.py
def load_params(i): if i == 0: return { "key" : "xxx", "output_dir" : "output", # ... } elif i == 1: return { "key" : "yyy", "output_dir" : "output2", # ... } #... else: raise RuntimeError(f"load_params: Invalid i parameter: {i}")
main.py
import sys from optparse import OptionParser def main(): parser = OptionParser() parser.add_option( "-i", "--config-index", metavar = "INT", type = "int", dest = "config_index", help = "Index of the configuration. 0 = ... ; 1 = ...", default = 0 ) (options, args) = parser.parse_args() print(f"options.config_index = {options.config_index}") params = load_params(options.config_index) print(params) # ... return 0 if __name__ == "__main__": sys.exit(main())
Exécution
(mando@silk) (~) $ python3 toto.py -i 1
options.config_index = 1
{'key': 'yyy', 'output_dir': 'output2'}
(mando@silk) (~) $ python3 toto.py --config-index 1
options.config_index = 1
{'key': 'yyy', 'output_dir': 'output2'}
(mando@silk) (~) $ python3 toto.py -i 0
options.config_index = 0
{'key': 'xxx', 'output_dir': 'output'}
(mando@silk) (~) $ python3 toto.py
options.config_index = 0
{'key': 'xxx', 'output_dir': 'output'}
Ici j'ai pris un entier mais tu peux imaginer travailler avec une chaîne, un booléan, bref ce qui est adapté à tes besoins (voir un tutoriel sur optparse). Ton programme peut bien évidemment avoir plusieurs options. On pourrait d'ailleur imaginer que tu aies un paramètre en ligne de commande pour chacun de tes paramètres (url de l'api, output_dir, etc...) + un paramètre qui les initialise toute en chargeant un fichier de configuration (ini ou json). On évite toutefois de mettre les clés en paramètres car sinon elles apparaissent en clair dans la table des processus.
Bonne chance
Ok, merci beaucoup.
J'ai donc adapté le script gen.py (ou main.py), pour récupérer les différents paramètres et les mettre dans des variables globales, comme ceci :
url = "" key = "" output_dir = "" # [...] def main(): # [...] global url url = params["url"] global key key = params["key"] global output_dir output_dir = params["output_dir"] return 0 # We launch the search for parameters main() # [...]
J'ai juste une petite question, la ligne
if __name__ == '__main__': sys.exit(main())
signifie que la fonction main est exécuté seulement si le script exécuté en ligne de commande, et non importé c'est cela ?
- Concernant ton script, je te déconseille l'utilisation de variables globales. C'est généralement une mauvaise habitude car ça nuit à la lisibilité (on ne voit pas l'ensemble des paramètres d'une fonction) et ça peut avoir des effets de bords gênant (programmation parallèle). Mieux vaut les passer explicitement en paramètres.
- Concernant les deux lignes en fin de fichier, oui cela sert quand on exécute le script python en ligne de commande.
- Est-ce que ton problème est résolu ou as-tu d'autres questions ?
Ces autres fonctions devraient simplement recevoir url, key etc en paramètre. Ça alourdit un peu la signature et l'appel des fonctions en questions, mais au moins on sait de quoi elles dépendent. Donc admettons que les fonctions en questions soient f(x, y) et g(x, y), que f a besoin de api et url, et que g à besoin de url et key, alors elles elles deviennent f(x, y, api, url) et g(x, y, url, key)
Ensuite, si ça a un sens de rassembler f, g, api, url et key, tu peux imaginer définir un objet qui aura api, url et key en attribut puis f et g en méthodes. En tant que méthodes, f et g auront accès à self.api, self.url, self.key.
class Gateway: def __init__(self, url, api, key): self.url = url self.api = api self.key = key def f(self, x, y): print(x, y, self.url, self.api) def f(self, x, y): print(x, y, self.api, self.key) gateway = Gateway("url", "api", "key") gateway.f(1, 2) gateway.g(3, 4)
Ainsi la signature de f et g est plus légère.