Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 29, 2011 22:55:23

aivs
От:
Зарегистрирован: 2011-05-26
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

Быстродействие хочу добиться, чтобы научиться писать программы с правильным кодом.
Версия той программы которую пишу на python, я уже написал на баше с использованием sed. Поэтому сейчас главный смысл - это обучение!



Офлайн

#2 Окт. 30, 2011 09:12:02

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

Желание писать “с правильным кодом” ортогонально желанию писать быстрые программы. Вот возьмем тот же readlines или построчное чтение. Если речь идет об обработке файлов большого размера либо большого количества файлов параллельно, то использование readlines категорически противопоказано из-за существенно больших требований к памяти по сравнению с чтением построчно. С точки зрения быстродействия, возможно, вариант с readlines будет быстрее. Какой код будет ‘правильным’ зависит от решаемой задачи.



Отредактировано (Окт. 30, 2011 09:13:21)

Офлайн

#3 Окт. 31, 2011 11:18:17

aivs
От:
Зарегистрирован: 2011-05-26
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

Вот вариант редактирования конфига без regexp.
Как работает:
1) Читаем все строки в файле, все таки с помощью readlines
2) Вычисляем номер строки, которая начинается начинается с нужного параметра, использую метод строки startswith(), который в каждой строке проверяет первую подстроку, при нахождении такой строки, поиск останавливается.
3) Разбиваем строку на подстроки, разделить “=”
4) У второй подстроки (значение) убираем пробелы, если они есть
5) Сохраняю старое значение (потом пригодится)
6) Изменяю значение и склеиваю обратно все в строку
7) Записываю в файл

#!/usr/bin/python

# edit_rcconf.py

""" Функция редактирования конфигурационного файла rc.conf,
вызывается: rcconf_edit("параметр","значение") """
def rcconf_edit(param, setting):

# Читаем все строки в файле
config = open('rc.conf').readlines()

# Вычисляем номер строки, которая начинается с gateway
num_line = 0 #Номер строки
for line in config:
# Если строка N num_line начинается со слова param
if config[num_line].startswith(param):
break
num_line+=1

# Разбиваем строку на слова
param_sett = config[num_line].split("=")

# Очищаем значение параметра от пробелом и сохраняем в переменную old_setting
old_setting = param_sett[1].strip()

# Заменяем строку "параметр = значение" на новую
param_sett[1] = setting + "\n"
config[num_line] = '='.join(param_sett)

# Записываем новый конфиг в файл
with open('rc.conf', 'w') as config_write:
config_write.writelines(config)

# Вызываем функцию редактрирования rc.conf
rcconf_edit("address", "192.168.1.116")
При однократном выполнении эта функция выполняется на десятитысячную секунду быстрее чем функция с re.



Офлайн

#4 Окт. 31, 2011 22:17:59

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

У вас же задача стоит несколько параметров поменять, разве нет? Будете так для каждого параметра делать?

Я бы делал как-нибудь так:

from os import linesep, rename

fname = 'rc.conf'
new_name = '%s.new' % fname
with open(fname) as inf, open(new_name, 'w') as outf:
for line in inf:
for name,value in (("interface", "eth0"), ("address", "192.168.1.100"),
("netmask", "255.255.255.0"), ("gateway", "192.168.1.1")):
if line.startswith(name):
line = "%s=%s%s" % (name, value, linesep)
break
outf.write(line)
rename(new_name, fname)
У меня на моем старом лэптопе X60s это занимает 0m0.038s. Вам нужно большее быстродействие? Сомневаюсь.



Отредактировано (Окт. 31, 2011 22:31:46)

Офлайн

#5 Ноя. 1, 2011 07:10:41

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

Ed
    for line in inf:
for name,value in (("interface", "eth0"), ("address", "192.168.1.100"),
("netmask", "255.255.255.0"), ("gateway", "192.168.1.1")):
if line.startswith(name):
line = "%s=%s%s" % (name, value, linesep)
break
outf.write(line)
я б тут через словарь сделал
    d = dict([("interface", "eth0"), ("address", "192.168.1.100"), ("netmask", "255.255.255.0"), ("gateway", "192.168.1.1")])
for line in inf:
name = line.split('=')[0].split()
if name in d:
line = "%s=%s%s" % (name, d[name], linesep)
outf.write(line)

Отредактировано (Ноя. 1, 2011 07:11:05)

Офлайн

#6 Ноя. 1, 2011 07:36:56

aivs
От:
Зарегистрирован: 2011-05-26
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

Да действительно, для каждого параметра вызывать функцию, не быстро получится. Использую предложенные варианты.
o7412369815963 чем словарь лучше в данной ситуации? Мне кажется словарь больше ресурсов потребляет, чем список ?!



Офлайн

#7 Ноя. 1, 2011 08:30:09

s0rg
От:
Зарегистрирован: 2011-06-05
Сообщения: 777
Репутация: +  25  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

Я бы предложил такой вариант:

#/usr/bin/env python
#-*-coding: utf8 -*-


class CfgParser(object):
'''
Dict-like unix config files parser

cfg = CfgParser('/etc/someconfig.cfg')
print cfg['SOMEVAL']
cfg['NEW_STR_VAL'] = 'somestring'
cfg['NEW_INT_VAL'] = 42

print cfg

fd = open('/etc/someconfig.cfg', 'w')
fd.write(repr(cfg))
fd.close()
'''

def __init__(self, config=None):
self._data = list()

if config is not None:
with open(config) as fd:
self.load_lines(fd)

def load_lines(self, iterable):
'''
Parse trough iterable that contains lines
'''
for line in iterable:
strp = line.strip()
if '=' not in strp or \
strp[0] in ('#', ';'):
self._data.append(('_COMMENT_', strp))
else:
name, value = strp.split('=')
self._data.append((name, value))

def _find_key(self, fkey):
'''
Find a key inside self._data
Returns: tuple (index, value)
or (None, None) if key not exists
'''
if fkey != '_COMMENT_':
for idx, key_val in enumerate(self._data):
key, val = key_val
if key == fkey:
return (idx, val.strip('\'\"'))
return (None, None)

def __getitem__(self, key):
_, val = self._find_key(key)
if val is None:
raise IndexError
return val

def __setitem__(self, key, value):
idx, _ = self._find_key(key)
val = ('"%s"' % value) if isinstance(value, basestring) else value
if idx is None:
self._data.append((key, val))
else:
self._data[idx] = (key, val)

def __delitem__(self, key):
idx, _ = self._find_key(key)
if idx is None:
raise IndexError
del self._data[idx]

def __repr__(self):
return '\n'.join(["%s = %s" % (key, val) if key != '_COMMENT_' else val
for key, val in self._data])


if __name__ == '__main__':
import sys

CONFIG_NAME = './rc.conf'

def main(argv=None):
cfg = CfgParser(CONFIG_NAME)

cfg['NEW_STRING'] = 'test'
cfg['NEW_INT'] = 89998
cfg['HARDWARECLOCK'] = 'remote_type'
print cfg

return 0

sys.exit(main(sys.argv))

Офлайн

#8 Ноя. 1, 2011 12:02:01

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

aivs
Да действительно, для каждого параметра вызывать функцию, не быстро получится. Использую предложенные варианты.
o7412369815963 чем словарь лучше в данной ситуации? Мне кажется словарь больше ресурсов потребляет, чем список ?!
В данной ситуации любой вариант подойдет т.к. входные данные и обработка смешных размеров.

А если вообще, то получение значения по ключу из словаря в сто-пицот раз быстрее чем поиск перебором.
т.е. тут "dict“ vs ”for name in xxx: if name == x"

Офлайн

#9 Ноя. 1, 2011 12:11:00

s0rg
От:
Зарегистрирован: 2011-06-05
Сообщения: 777
Репутация: +  25  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

o7412369815963
А если вообще, то получение значения по ключу из словаря в сто-пицот раз быстрее чем поиск перебором.
Это да - но нужно сохранить первоначальную структуру данных.

Офлайн

#10 Ноя. 1, 2011 12:19:36

aivs
От:
Зарегистрирован: 2011-05-26
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

Парсинг конфигурационного файла. regexp или другое

s0rg
Это да - но нужно сохранить первоначальную структуру данных.
Именно так!



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version