2009-05-29 6 views
28

référence sur this question, j'ai même -mais pas le problème excursionnistes ..La meilleure façon de récupérer les valeurs des variables à partir d'un fichier texte - Python - JSON

Sur mon chemin, je vais avoir un certain fichier texte, structuré comme:

var_a: 'home' 
var_b: 'car' 
var_c: 15.5 

et j'ai besoin que python lire le fichier, puis créer une variable nommée var_a avec la valeur « maison », et ainsi de suite.

Exemple:

#python stuff over here 
getVarFromFile(filename) #this is the function that im looking for 
print var_b 
#output: car, as string 
print var_c 
#output 15.5, as number. 

Est-ce possible, je veux dire, même garder le type var?

Notez que j'ai toute la liberté de la structure du fichier texte, je peux utiliser le format que j'aime si celui que j'ai proposé n'est pas le meilleur.

EDIT: le ConfigParser peut être une solution, mais je ne l'aime pas tellement, parce que dans mon script que je vais devoir alors de se référer aux variables dans le fichier avec

config.get("set", "var_name") 

Mais ce que j'adorerai, c'est de me référer directement à la variable, comme je l'ai déclaré dans le script python ...

Il existe un moyen d'importer le fichier en tant que dictionnaire python? Oh, dernière chose, gardez à l'esprit que je ne sais pas exactement combien de variables aurais-je dans le fichier texte. : Je m'intéresse beaucoup à la solution JSON de stephan, car de cette façon le fichier texte peut être lu simplement avec d'autres langages (PHP, puis via JavaScript AJAX, par exemple), mais j'échoue dans quelque chose en agissant cette solution:

#for the example, i dont load the file but create a var with the supposed file content 
file_content = "'var_a': 4, 'var_b': 'a string'" 
mydict = dict(file_content) 
#Error: ValueError: dictionary update sequence element #0 has length 1; 2 is required 
file_content_2 = "{'var_a': 4, 'var_b': 'a string'}" 
mydict_2 = dict(json.dump(file_content_2, True)) 
#Error: 
#Traceback (most recent call last): 
#File "<pyshell#5>", line 1, in <module> 
#mydict_2 = dict(json.dump(file_content_2, True)) 
#File "C:\Python26\lib\json\__init__.py", line 181, in dump 
#fp.write(chunk) 
#AttributeError: 'bool' object has no attribute 'write' 

En quel type de problème puis-je tomber au format JSON? Et, comment puis-je lire un tableau JSON dans un fichier texte, et le transformer dans un dict python?

P.S: Je n'aime pas la solution utilisant les fichiers .py; Je préférerais .txt, .inc, .que ce n'est pas restrictif à une langue.

+0

Vous ne pouvez pas gérer sans n'importe quels modules d'importation ... vous pouvez gérer avec le module sys, mais ce ne serait pas aussi bien que les autres solutions suggérées :) – workmad3

+0

ok, ce n'est pas un gros problème – Strae

+0

concernant votre Edit2: vous voulez the_dict = json.loads ('{"var_a": 4, "var_b": "une chaîne"}'). Pls note que j'ai changé "et" – stephan

Répondre

14

Chargez votre fichier avec JSON ou PyYAML dans un dictionnaire the_dict (voir doc pour JSON ou PyYAML pour cette étape, les deux peuvent stocker type de données) et ajouter le dictionnaire à votre dictionnaire global, par exemple en utilisant globals().update(the_dict).

Si vous le souhaitez dans un dictionnaire local au lieu (par exemple dans une fonction), vous pouvez le faire comme ceci:

for (n, v) in the_dict.items(): 
    exec('%s=%s' % (n, repr(v))) 

aussi longtemps qu'il est sûr à utiliser exec. Sinon, vous pouvez utiliser le dictionnaire directement.

+2

Pouvez-vous montrer une exemple basilaire? – Strae

+2

Un idiome plus court est globals(). update (the_dict) ou locals(). update (the_dict) –

+0

Merci d'avoir signalé ce problème. ut pour les globals(). Amended ma réponse. locals() est cependant en lecture seule (voir http://docs.python.org/library/functions.html#locals). – stephan

16

Vous pouvez traiter votre fichier texte en tant que module python et le charger dynamiquement en utilisant imp.load_source:

import imp 
imp.load_source(name, pathname[, file]) 

Exemple:

// mydata.txt 
var1 = 'hi' 
var2 = 'how are you?' 
var3 = { 1:'elem1', 2:'elem2' } 
//... 

// In your script file 
def getVarFromFile(filename): 
    import imp 
    f = open(filename) 
    global data 
    data = imp.load_source('data', '', f) 
    f.close() 

# path to "config" file 
getVarFromFile('c:/mydata.txt') 
print data.var1 
print data.var2 
print data.var3 
... 
+0

C'est exactement la solution que je cherchais à fournir une solution élégante à un problème noueux.Merci, Nick –

+0

bienvenue @Adam :) Cheers! –

21

Utilisez ConfigParser.

Votre config:

[myvars] 
var_a: 'home' 
var_b: 'car' 
var_c: 15.5 

Votre code python:

import ConfigParser 

config = ConfigParser.ConfigParser() 
config.read("config.ini") 
var_a = config.get("myvars", "var_a") 
var_b = config.get("myvars", "var_b") 
var_c = config.get("myvars", "var_c") 
+0

Juste édité - de cette façon est bien, mais si possible je cherche un autre qui me laisserait utiliser les variables d'une manière utile – Strae

+1

J'ai mis à jour la réponse pour vous montrer comment les utiliser comme –

+0

Ou vous pouvez prendre la classe Bunch de http://code.activestate.com/recipes/52308/ et la pirater pour qu'elle soit récursive, donc vous pouvez vous référer directement à config.myvars.var_a –

53

Mais ce que je vais aimer est de se référer à la direclty variable, comme je l'ai déclaré dans le script python ..

En supposant que vous êtes heureux de changer votre syntaxe légèrement, il suffit d'utiliser python et importez le module "config".

# myconfig.py: 

var_a = 'home' 
var_b = 'car' 
var_c = 15.5 

Puis faire

from myconfig import * 

Et vous pouvez les référencer par nom dans votre contexte actuel.

+3

+1, C'est absolument le meilleur moyen de faire des fichiers de configuration. Pas besoin de développer votre propre syntaxe de config, les analyseurs de config, les chargeurs de config etc. quand vous pouvez simplement réutiliser les parties centrales de python! – Simon

+3

+1 oui, tant que vous pouvez faire confiance à votre fichier de configuration et n'avez pas besoin de portabilité – stephan

+2

Commodité et flexibilité ++ vs. sécurité -: dans certaines situations, c'est génial, dans d'autres ... moins. – mavnn

1

Ce que vous voulez semblent vouloir est le suivant, mais cela est DECONSEILLE:

>>> for line in open('dangerous.txt'): 
...  exec('%s = %s' % tuple(line.split(':', 1))) 
... 
>>> var_a 
'home' 

Cela crée un comportement assez similaire à PHP de register_globals et a donc les mêmes problèmes de sécurité. En outre, l'utilisation de exec que j'ai montré permet l'exécution de code arbitraire. Seulement utilisez ceci si vous êtes absolument sûr que le contenu du fichier texte peut être approuvé en toutes circonstances.

Vous devriez vraiment envisager de lier les variables non à la portée locale, mais à un objet, et utiliser une bibliothèque qui analyse le contenu du fichier de sorte qu'aucun code n'est exécuté. Donc: aller avec l'une des autres solutions fournies ici.

(S'il vous plaît noter: j'ajouté cette réponse non pas comme une solution, mais comme un explicite non-solution.)

+0

Oui, merci pour la raccomandation, j'ai banni la fonction exec à la fois de mes scripts php et python il ya longtemps;) – Strae

2

Quelle est la fiabilité de votre format? Si le séparateur est toujours exactement ':', les opérations suivantes. Sinon, une expression rationnelle relativement simple devrait faire l'affaire.

Tant que vous travaillez avec des types de variables assez simples, la fonction eval de Python rend les variables persistantes aux fichiers étonnamment faciles.

(Ci-dessous vous donne un dictionnaire, btw, que vous avez mentionné était l'une de vos solutions préférées).

def read_config(filename): 
    f = open(filename) 
    config_dict = {} 
    for lines in f: 
     items = lines.split(': ', 1) 
     config_dict[items[0]] = eval(items[1]) 
    return config_dict 
+0

Je peux écrire le fichier texte exaclty comme je veux, le format var : value est juste par exemple, si les autres formats sont meilleurs, est libre de suggérer – Strae

+0

Tant que c'est cohérent, et que la valeur est de la forme générée par repr (variable) cela n'a pas vraiment d'importance pour cette méthode. Choisissez simplement un séparateur qui ne fera jamais partie du nom de la variable et utilisez-le dans la méthode split. – mavnn

2

Supposons que vous avez un fichier appelé "test.txt » avec:

a=1.251 
b=2.65415 
c=3.54 
d=549.5645 
e=4684.65489 

Et vous voulez trouver une variable (a, b, c, d ou e):

ffile=open('test.txt','r').read() 

variable=raw_input('Wich is the variable you are looking for?\n') 

ini=ffile.find(variable)+(len(variable)+1) 
rest=ffile[ini:] 
search_enter=rest.find('\n') 
number=float(rest[:search_enter]) 

print "value:",number 
+0

Ne fonctionnera pas si vous avez des lettres au lieu de chiffres et si vous imprimez simplement un nombre à partir d'un fichier. Ce n'est malheureusement pas la bonne réponse. –

5

Les autres solutions publiées ici ne fonctionnent pas pour moi, parce que :

  • i seulement les paramètres nécessaires à partir d'un fichier pour un script normale
  • import * ne fonctionne pas pour moi, comme je l'ai besoin d'un moyen de les remplacer en choisissant un autre fichier
  • Juste un fichier avec une dict n'était pas bien, car j'avais besoin de commentaires.

Je fini par utiliser Configparser et globals().update()

fichier de test:

#File parametertest.cfg: 
[Settings] 
#Comments are no Problem 
test= True 
bla= False #Here neither 

#that neither 

Et c'est mon script de démonstration:

import ConfigParser 

cfg = ConfigParser.RawConfigParser() 
cfg.read('parametertest.cfg')  # Read file 

#print cfg.getboolean('Settings','bla') # Manual Way to acess them 

par=dict(cfg.items("Settings")) 
for p in par: 
    par[p]=par[p].split("#",1)[0].strip() # To get rid of inline comments 

globals().update(par) #Make them availible globally 

print bla 

Il est juste un fichier avec une section maintenant , mais ce sera facile à adopter.

espère que ce sera utile pour quelqu'un :)

+0

fonctionne très bien! Merci – gtRfnkN

+0

J'ai trouvé cette solution le meilleur. Je peux laisser l'équipe mettre à jour le fichier config.ini (moins effrayant que .cfg) et je n'ai pas besoin de m'inquiéter de ne pas utiliser de guillemets, de laisser des espaces, de mettre des messages pour les coéquipiers dans les commentaires, etc. . Merci! – nikhilvj

0

La réponse de hbn ne fonctionnera pas hors de la case si le fichier à charger is in a subdirectory ou is named with dashes.

Dans ce cas, vous pouvez envisager cette alternative:

exec open(myconfig.py).read() 

Ou le plus simple, mais dépréciés dans python3:

execfile(myconfig.py) 

Je pense que l'avertissement de Stephan202 applique aux deux options, bien que, et peut-être la boucle sur les lignes est plus sûr.

Questions connexes