AttributeError: объект ‹Class› не имеет атрибута вне цикла?

У меня есть класс под названием state_class:

class state_class:
  def __init__(self, state_name): 

    self.state_name = state_name

    @property
    def state_col(self):
        """state_col getter"""
        return self._state_col

    @state_col.setter
    def state_col(self):
        """state_col setter"""
        self._state_col = state_col

Я запускаю этот класс внутри оператора if и цикла for:

for region in regions:
  if region == '1':
    for region in regions:
        for col in range(prelim_sheet.ncols):
          if (prelim_sheet.cell_value(0, col) == r.region_name):
           ...
          else:
            for state in state_list:
                if state.strip() == 'NewHampshire':  
                    s = state_class(state)
                    if ((prelim_sheet.cell_value(0, col)).replace(" ", "") == s.state_name):
                        s.state_col = col
                        print(s.state_col)
                        ...

Как видите, внизу у меня есть оператор печати для s.state_col, который выводит правильное значение. Но если я попытаюсь вызвать s.state_col вне циклов if и for, я получу ошибку:

AttributeError Traceback (последний последний вызов) в ----> 1 s.state_col

AttributeError: объект «state_class» не имеет атрибута «state_col»

Я проверил это вне циклов, и он отлично работает:

s = state_class('NewHampshire')
col = 20
s.state_col = col
print(s.state)
>>> 20

Есть ли причина, по которой он устанавливает state_col внутри цикла или позволяет мне вызывать его снаружи? Как я могу решить эту проблему?


person gwydion93    schedule 14.11.2019    source источник
comment
В вашем случае вызов геттера перед вызовом сеттера вызовет это исключение, потому что в противном случае self._state_col не существует, что полностью согласуется с концепцией программирования с отслеживанием состояния. Возможно, это плохой выбор дизайна: вы должны либо обрабатывать исключение, либо избегать такого программирования с отслеживанием состояния. Кстати, все атрибуты должны быть объявлены при инициализации объекта. Вы всегда можете назначить None (или любое другое пустое значение) для сброса переменных и обработать эту ситуацию в геттере.   -  person Eli Korvigo    schedule 14.11.2019
comment
Я немного смущен по поводу лучшего дизайна. Я новичок в использовании classes, и я не уверен, что вы имеете в виду, говоря о вызове геттера перед сеттером. Вы можете проиллюстрировать?   -  person gwydion93    schedule 14.11.2019


Ответы (2)


Как сказал @Eli Korvigo, вы должны инициализировать все переменные в функции init класса, иначе они не существуют, пока вы их не установите.

редактировать:

Я посмотрел ближе к вашему коду, и отступ был неправильным, а функция установки требует ввода. Что менее важно, имена классов должны быть CamelCase. Теперь этот код должен работать:

class StateClass:
    def __init__(self, state_name):
        self.state_name = state_name
        self._state_col = None

    @property
    def state_col(self):
        """state_col getter"""
        return self._state_col

    @state_col.setter
    def state_col(self, s):
        """state_col setter"""
        self._state_col = s
person big_bad_bison    schedule 14.11.2019
comment
Хорошо, я только что сделал именно это, и я все еще получаю ту же ошибку AttributeError: 'state_class' object has no attribute 'state_col'. - person gwydion93; 14.11.2019
comment
@gwydion93 gwydion93, не уверен, заметили ли вы, но я недавно отредактировал свой комментарий, чтобы исправить проблему. Приношу свои извинения за то, что не информировал вас. - person big_bad_bison; 15.11.2019

После долгих поисков и ошибок я определил, что суть этой проблемы не в геттерах и сеттерах state_class (они работают внутри цикла), а в операторе else, который я поставил в конце.

for col in range(prelim_sheet.ncols):
    if (prelim_sheet.cell_value(0, col) == r.region_name):
       ...
    else:
        for state in state_list:
            if state.strip() == 'NewHampshire':  
                s = state_class(state)
                if ((prelim_sheet.cell_value(0, col)).replace(" ", "") == s.state_name):
                    s.state_col = col
                    print(s.state_col)

По сути, это говорит о том, что если первый критерий не соблюдается, продолжайте прокручивать столбцы (около 34 столбцов), и в процессе создания экземпляра класса происходит сбой. Чтобы исправить это, я добавил несколько вещей. 1) Я изменил оператор else' to anelif` и установил некоторые критерии. 2) Я добавил динамический словарь, который позволит мне хранить экземпляр класса для каждого штата (использование «Нью-Гемпшир» было только для целей тестирования). Хотя я думаю, что решение @big_bad_bison может сработать (и я отдаю им должное), мое новое решение на самом деле лучше всего работает для меня в этой ситуации. Спасибо за помощь:

    state_map = {}
    for col in range(prelim_sheet.ncols):
        col_name = prelim_sheet.cell_value(0, col)

        if (col_name == region_map[region].region_name):
            region_map[region].region_total_col = col
            region_map[region].detailed_col = region_map[region].region_total_col
            region_map[region].approx_col = region_map[region].region_total_col + 1
            region_map[region].unmapped_col = region_map[region].region_total_col + 2
            region_map[region].total_col = region_map[region].region_total_col + 3


        elif (col_name.replace(" ", "") in region_map[region].region_long_list):
            state = col_name
            state_map[state] = state_class(state)
            state_map[state].state_col = col
            state_map[state].detailed_col = state_map[state].state_col
            state_map[state].approx_col = state_map[state].state_col + 1
            state_map[state].unmapped_col = state_map[state].state_col + 2
            state_map[state].total_col = state_map[state].state_col + 3    
            print("The col is {}".format(str(col)),state_map[state].state_col, state)

        region_map[region].state_map = state_map
person gwydion93    schedule 15.11.2019