Как использовать __setattr__ & __getattr__ для значений INI карты? - PullRequest
4 голосов
/ 14 мая 2009

Я хочу отобразить INI-файл как объект Python. Так что если файл имеет:

[UserOptions]
SampleFile = sample.txt
SamplePort = 80
SampleInt = 1
Sample = Aja
SampleDate = 10/02/2008

Тогда я хочу:

c = Configuration('sample.ini')

c.UserOptions.SamplePort = 90

Я ищу setattr , но получаю ошибку рекурсии.

Вот что у меня есть:

class Configuration:
    def __init__ (self, fileName):
        cp = SafeConfigParser()
        cp.read(fileName)
        self.__parser = cp
        self.fileName = fileName

    def __getattr__ (self, name):
        if name in self.__parser.sections():
            return Section(name, self.__parser)
        else:
            return None

    def __str__ (self):
        p = self.__parser
        result = []
        result.append('<Configuration from %s>' % self.fileName)
        for s in p.sections():
            result.append('[%s]' % s)
            for o in p.options(s):
                result.append('%s=%s' % (o, p.get(s, o)))
        return '\n'.join(result)

class Section:
    def __init__ (self, name, parser):
        self.__name = name
        self.__parser = parser

    def __getattr__ (self, name):
        if self.__dict__.has_key(name):       # any normal attributes are handled normally
            return __getattr__(self, item)
        else:
            return self.__parser.get(self.name, name)

    def __setattr__(self, item, value):
        """Maps attributes to values.
        Only if we are initialised
        """
        if self.__dict__.has_key(item):       # any normal attributes are handled normally
            dict.__setattr__(self, item, value)
        else:
            self.__parser.set('UserOptions',item, value)

Теперь мне интересно, почему в self.__parser.set('UserOptions',item, value) я получаю ошибку. Я читаю в документации по питонам и не понимаю, что делать. Я подозреваю, что мне нужно сохранить dict с именем поля и сначала посмотреть, но как?

Ответы [ 2 ]

4 голосов
/ 14 мая 2009

Ваша проблема в Section.__init__. Когда вы устанавливаете self.__name = name, он вызывает ваш метод __setattr__, не находит ключ в __dict__, поэтому он переходит к

 self.__parser.set('UserOptions',item, value)

Так что теперь ему нужно self.__parser.

Который еще не был установлен. Поэтому он пытается получить его, используя __getattr__. Который отправляет его в поисках self.__parser. Который еще не был установлен. Поэтому он пытается получить его, используя __getattr__. Итак ... вы поняли: -)

Один из способов избежать этого - добавить условие в Section.__setattr__, как это

if item.startswith('_') or self.__dict__.has_key(item):
   ^^^^^^^^^^^^^^^^^^^^^^^
   ...

, который обеспечит правильную настройку __name и __parser при инициализации.

4 голосов
/ 14 мая 2009

Вы пытаетесь получить разделы по запросу. Но намного проще перебирать разделы и параметры и добавлять их как атрибут в __init__. Я отредактировал мой пример для поддержки setattr. Ваша проблема объяснена здесь вы назначаете атрибуты в __setattr__, в то время как вы должны использовать __dict__ вместо

from ConfigParser import  SafeConfigParser

class Section:
    def __init__(self, name, parser):
        self.__dict__['name'] = name
        self.__dict__['parser'] = parser

    def __setattr__(self, attr, value):
        self.__dict__[attr] = str(value)
        self.parser.set(self.name, attr, str(value))

class Configuration(object):
    def __init__(self, fileName):
        self.__parser = SafeConfigParser()
        self.__parser.read(fileName)
        self.fileName = fileName
        for section in self.__parser.sections():
            setattr(self, section, Section(section, self.__parser))
            for option in self.__parser.options(section):
                setattr(getattr(self, section), option,
                        self.__parser.get(section, option))

    def __getattr__(self, attr):
        self.__parser.add_section(attr)
        setattr(self, attr, Section(attr, self.__parser))
        return getattr(self, attr)

    def save(self):
        f = open(self.fileName, 'w')
        self.__parser.write(f)
        f.close()

c = Configuration('config.ini')

print dir(c) -> will print all sections
print dir(c.UserOptions) -> will print all user options
print c.UserOptions.sampledate

c.new.value = 10
c.save()
...