0

I have a class called 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

I initiate this class inside a an if statement and for loop:

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

As you can see, at the bottom, I have a print statement for s.state_col, which print out the correct value. But if I try to call s.state_col outside of the if and for loops, I get an error:

AttributeError Traceback (most recent call last) in ----> 1 s.state_col

AttributeError: 'state_class' object has no attribute 'state_col'

I have tested this outside the loops and it works fine:

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

Is there a reason why it set state_col inside the loop or let me call it outside? How can I resolve this?

2
  • 1
    In your case, calling the getter before ever calling the setter will invoke that exception, because self._state_col does not exist otherwise, which is perfectly consistent with the concept of stateful programming. This is arguably a poor design choice: you should either handle the exception or avoid that kind of stateful programming. By the way, all attributes should be declared during object initialisation. You can always assign None (or any other "empty" value) to unset variables and handle that situation in the getter. Commented Nov 14, 2019 at 1:36
  • I am a little confused about a better design. I'm somewhat new using classes and I'm not sure what you mean about calling the getter before the setter. Can you illustrate? Commented Nov 14, 2019 at 1:48

2 Answers 2

1

As @Eli Korvigo said, you should initialize all variables in the init function of a class, otherwise they do not exist until you set them.

edit:

I looked closer to your code and the indenting was incorrect, and the setter function requires an input. Less important, class names should be CamelCase. This code should now work:

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
Sign up to request clarification or add additional context in comments.

2 Comments

OK, I just did exactly that and I am still getting the same AttributeError: 'state_class' object has no attribute 'state_col' error.
@gwydion93, not sure if you noticed but I edited my comment a while ago to fix the issue. My apologies for not informing you.
0

After much trail and error, I determined that the crux of this problem was not in the state_class getters and setters (they work inside the loop), but the else statement I put at the end.

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)

Essentially, what this says is, if the first criteria is not met, keep on rolling through the cols (there are about 34 columns) and the class instantiation gets messed up in the process. To fix this, I added a few things. 1) I changed the else' to anelif` statement and set some criteria. 2) I added a dynamic dictionary that will allow me to store an instance of the class for every state (Using 'NewHampshire' was just for testing purposes). While I think @big_bad_bison 's solution may work (and I give them credit), my new solution is actually what works best for me in this situation. Thanks for the assistance:

    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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.