Лучший способ получить значения переменных из текстового файла?

Ссылаясь на этот вопрос, у меня есть аналогичная, но не такая же проблема. ..

По дороге у меня будет текстовый файл со следующей структурой:

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

И мне нужно, чтобы питон прочитал файл, а затем создал переменную с именем var_a со значением «home» и так далее.

Пример:

#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.

Возможно ли это, я имею в виду, даже сохранить тип var?

Обратите внимание, что у меня есть полная свобода в отношении структуры текстового файла, я могу использовать формат, который мне нравится, если тот, который я предложил, не самый лучший.

РЕДАКТИРОВАТЬ: ConfigParser может быть решением, но мне это не очень нравится, потому что в моем сценарии мне придется тогда ссылаться на переменные в файле с помощью

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

Но что мне нравится, так это ссылаться на переменную напрямую, как я объявил в скрипте python ...

Есть ли способ импортировать файл как словарь Python?

О, последнее, имейте в виду, что я точно не знаю, сколько переменных у меня было бы в текстовом файле.

Редактировать 2: меня очень интересует решение Stephan JSON, потому что в этом случае текстовый файл можно было бы просто читать на других языках (например, PHP, затем через AJAX JavaScript), но я не могу что-то при действии этого решения:

#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'

В какие проблемы я могу попасть с форматом JSON? И как я могу прочитать массив JSON в текстовом файле и преобразовать его в Python dict?

P.S: Мне не нравится решение, использующее файлы .py; Я предпочитаю .txt, .inc и все, что не ограничивается одним языком.


person Strae    schedule 29.05.2009    source источник
comment
Вы не можете обойтись без каких-либо модулей импорта ... вы могли бы обойтись только с модулем sys, но это было бы не так хорошо, как другие предлагаемые решения :)   -  person workmad3    schedule 29.05.2009
comment
относительно вашего Edit2: вам нужен the_dict = json.loads ('{var_a: 4, var_b: a string}'). Пожалуйста, обратите внимание, что я переключил и '.   -  person stephan    schedule 29.05.2009
comment
И это именно то, что я хочу. Спасибо чувак!   -  person Strae    schedule 29.05.2009


Ответы (11)


Загрузите файл с помощью JSON или PyYAML в словарь the_dict (см. документ для JSON или PyYAML для этого шага, оба могут хранить тип данных) и добавить словарь в свой глобальный словарь, например используя globals().update(the_dict).

Если вы хотите, чтобы это было в локальном словаре (например, внутри функции), вы можете сделать это следующим образом:

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

пока безопасно использовать exec. В противном случае вы можете использовать словарь напрямую.

person stephan    schedule 29.05.2009
comment
Более короткая идиома - globals (). Update (the_dict) или locals (). Update (the_dict). - person Jouni K. Seppänen; 29.05.2009
comment
Спасибо, что указали на это для globals (). Исправил свой ответ. Однако locals () доступен только для чтения (см. docs.python.org/library/functions. html # locals). - person stephan; 29.05.2009
comment
На самом деле это не только для чтения (я использовал его сам), но, по-видимому, есть обстоятельства, при которых запись в него не работает. Спасибо за указание на это. - person Jouni K. Seppänen; 31.05.2009

Но что мне нравится, так это ссылаться на переменную direclty, как я объявил в скрипте python ..

Предполагая, что вы готовы немного изменить свой синтаксис, просто используйте python и импортируйте модуль «config».

# myconfig.py:

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

Тогда сделай

from myconfig import *

И вы можете ссылаться на них по имени в вашем текущем контексте.

person hbn    schedule 29.05.2009
comment
+1, это абсолютно лучший способ делать файлы конфигурации. Нет необходимости увеличивать свой собственный синтаксис конфигурации, парсеры конфигурации, загрузчики конфигурации и т. Д., Когда вы можете просто повторно использовать основные части python! - person Simon; 29.05.2009
comment
+1 да, если вы можете доверять своему файлу конфигурации и не нуждаетесь в переносимости - person stephan; 29.05.2009
comment
Удобство и гибкость ++ против безопасности -: в одних ситуациях это здорово, в других ... меньше. - person mavnn; 29.05.2009
comment
Я должен отказаться от этого решения, потому что я не хочу ограничивать файл только python, я думаю, что лучше использовать общий формат файла (.txt, .inc, .whatever), к которому можно получить доступ и на других языках (со всеми безопасная мера, которую будет означать это решение). В любом случае я буду помнить об этом на будущее - person Strae; 29.05.2009
comment
вы также теряете поддержку записи в случае, если вы изменяете параметр в программном обеспечении и хотите сохранить изменения на диск - person Peter Gibson; 13.04.2011
comment
Это самый простой вариант, который я когда-либо видел. - person dave; 24.04.2016

Используйте ConfigParser.

Ваш конфиг:

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

Ваш код на 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")
person Igor Krivokon    schedule 29.05.2009
comment
Только что отредактировал - этот способ хорош, но, если возможно, я ищу другого, который позволил бы мне использовать переменные полезным способом - person Strae; 29.05.2009
comment
Я обновил ответ, чтобы показать вам, как использовать их в качестве переменных. - person Igor Krivokon; 29.05.2009
comment
Или вы можете взять класс Bunch из code.activestate.com/recipes/52308 и взломать он должен быть рекурсивным, поэтому вы можете напрямую обращаться к config.myvars.var_a. - person Jouni K. Seppänen; 29.05.2009

Вы можете рассматривать свой текстовый файл как модуль Python и динамически загружать его с помощью _ 1_:

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

Пример:

// 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
...
person Nick Dandoulakis    schedule 29.05.2009
comment
Это именно то решение, которое я искал, чтобы предоставить элегантное решение сложной проблемы. Спасибо, Ник. - person Adam Crossland; 04.03.2012
comment
Что стало с importlib? Бес устарел - person Rho Phi; 03.09.2020
comment
@RhoPhi, importlib не пробовал. Ознакомьтесь с Импортировать произвольный исходный файл Python. Python 3.3+ - person Nick Dandoulakis; 03.09.2020

Другие решения, размещенные здесь, не сработали для меня, потому что:

  • мне просто нужны были параметры из файла для обычного скрипта
  • import * у меня не сработало, так как мне нужен способ переопределить их, выбрав другой файл
  • Просто файл с dict не подходил, так как мне нужны были комментарии в нем.

В итоге я использовал Configparser и globals().update()

Тестовый файл:

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

#that neither

И это мой демонстрационный сценарий:

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

Сейчас это только для файла с одним разделом, но его легко адаптировать.

Надеюсь, это будет кому-то полезно :)

person SolarSimon    schedule 03.08.2012
comment
Я нашел это решение лучшим. Я могу позволить команде обновлять файл config.ini (менее страшно, чем .cfg), и мне не нужно беспокоиться о том, что они не используют правильные кавычки, оставляют пробелы, они могут помещать любые сообщения для товарищей по команде в комментарии и т. Д. . Спасибо! - person Nikhil VJ; 21.01.2018

Предположим, у вас есть файл под названием "test.txt" с:

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

И вы хотите найти переменную (a, b, c, d или 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
person JorgeGarza    schedule 22.03.2012
comment
Не будет работать, если у вас есть буквы вместо цифр, а также вы просто печатаете число из файла. К сожалению, это неправильный ответ. - person Marco smdm; 04.04.2017

Насколько надежен ваш формат? Если разделителем всегда является «:», работает следующее. В противном случае сравнительно простое регулярное выражение должно сработать.

Пока вы работаете с довольно простыми типами переменных, функция eval в Python на удивление упрощает сохранение переменных в файлах.

(Ниже приведен словарь, кстати, который, как вы упомянули, был одним из ваших предпочтительных решений).

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
person mavnn    schedule 29.05.2009
comment
Я могу написать текстовый файл точно так, как хочу, формат var: value - это просто, например, если другие форматы лучше, не стесняйтесь предлагать - person Strae; 29.05.2009
comment
Пока он непротиворечив и значение имеет форму, сгенерированную repr (переменная), это не имеет особого значения для этого метода. Просто выберите разделитель, который никогда не будет частью имени переменной, и используйте его в методе разделения. - person mavnn; 29.05.2009

Ответ hbn не будет работать из коробки, если файл для загрузки находится в подкаталоге или именуется тире.

В таком случае вы можете рассмотреть такую ​​альтернативу:

exec open(myconfig.py).read()

Или более простой, но устаревший в python3:

execfile(myconfig.py)

Я предполагаю, что предупреждение Stephan202 относится к обоим вариантам, и, возможно, цикл по строкам более безопасен.

person Skippy le Grand Gourou    schedule 20.02.2016
comment
@BrandonFrenchak Только для Python3. ;) Но об этом стоит упомянуть. - person Skippy le Grand Gourou; 31.12.2019

Простой способ чтения переменных из текстового файла с помощью стандартной библиотеки:

# Get vars from conf file
var = {}
with open("myvars.txt") as conf:
        for line in conf:
                if ":" in line:
                        name, value = line.split(":")
                        var[name] = str(value).rstrip()
globals().update(var)

По умолчанию каждая переменная читается как строка. Если вам нужно преобразовать их как буквальные переменные (например, списки / кортежи / bool), вам нужно будет использовать модуль ast:

import ast
ast.literal_eval(varname)
person Med Shah    schedule 18.02.2021

Похоже, что вам нужно следующее, но это НЕ РЕКОМЕНДУЕТСЯ:

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

Это создает несколько похожее поведение на register_globals PHP и, следовательно, имеет такую ​​же безопасность. вопросы. Кроме того, использование exec, которое я показал, позволяет выполнять произвольный код. Используйте это только в том случае, если вы абсолютно уверены, что содержимому текстового файла можно доверять при любых обстоятельствах.

Вам действительно следует рассмотреть возможность привязки переменных не к локальной области видимости, а к объекту, и использовать библиотеку, которая анализирует содержимое файла так, чтобы код не выполнялся. Итак: используйте любое из других решений, представленных здесь.

(Обратите внимание: я добавил этот ответ не как решение, а как явное не решение.)

person Community    schedule 29.05.2009
comment
Да, спасибо за raccomandation, я давно запретил функцию exec как в моих скриптах php, так и в скриптах python;) - person Strae; 29.05.2009

Если ваши данные имеют регулярную структуру, вы можете читать файл построчно и заполнять свой любимый контейнер. Например:

Допустим, у ваших данных есть 3 переменных: x, y, i.

Файл содержит n таких данных, каждая переменная в отдельной строке (3 строки на запись). Вот две записи:

384
198
0
255
444
2

Вот как вы считываете данные вашего файла в список. (Читаем по тексту, так что бросай соответственно.)

data = []
try:
    with open(dataFilename, "r") as file:
        # read data until end of file
        x = file.readline()
        while x != "":
            x = int(x.strip())    # remove \n, cast as int

            y = file.readline()
            y = int(y.strip())

            i = file.readline()
            i = int(i.strip())

            data.append([x,y,i])

            x = file.readline()

except FileNotFoundError as e:
    print("File not found:", e)

return(data)
person Greg    schedule 24.02.2020