The basic set-up is:

class A():
    def __init__(self):
        self.var = 1
    
    @staticmethod
    def do_stuff_with_var(self): # A method which uses self.var
        ...

class B(A):
    def __init__(self):
        A.__init__(self)

b1 = B()
b2 = B()
list_of_B_instances = [b1, b2]

for instance in list_of_B_instances:
    instance.do_stuff_with_var(instance)

However the last line of code raises the following error:

AttributeError: class B has no attribute 'var'

Why is this so? I thought that a subclass inherited all data attributes from its superclass. Or is this error raised because the list_of_B_instances does not actually contain the B objects themselves, but rather references those objects?

Keep in mind that not only am I new to Python, but I am also new to programming in general, and for that reason, you may have to dumb things down a bit for me to understand them.

Recommended Answers

All 8 Replies

You're going to have to post the code for do_stuff_with_var. Otherwise we'd just be guessing.

Try taking a look at this.

class A():
    def __init__(self):
        self.var = 1

    def do_stuff_with_var(self):
        print self.var

class B(A):
    def __init__(self):
        A.__init__(self)
        self.var = A().var

    def do_stuff_with_var(self):
        A.do_stuff_with_var(self)

b1 = B()
b1.do_stuff_with_var()

You're going to have to post the code for do_stuff_with_var. Otherwise we'd just be guessing.

Alright, if we are going to go down that road, let me give a little background. I am currently trying to make a Minesweeper clone in Python using Tkinter. I am doing this to get a handle on the basics of OOP in Python. I will try to post only what is relevant but be prepared to sift through some obfuscated code.

...
class PySweeperButton(Button):
    def __init__(self, location):
        Button.__init__(self, command=self.clicked, width=1, height=1)
        self.location = location
        self.col, self.row = self.location

     ...

    @staticmethod
    def find_adjacent_cells(self):
        adj_cells = []
        adj_cells.append((self.col - 1, self.row -1 ))
        adj_cells.append((self.col, self.row -1 ))
        adj_cells.append((self.col + 1, self.row - 1))
        adj_cells.append((self.col - 1, self.row))
        adj_cells.append((self.col + 1, self.row))
        adj_cells.append((self.col - 1, self.row + 1))
        adj_cells.append((self.col, self.row + 1))
        adj_cells.append((self.col + 1, self.row + 1))
        return adj_cells

class BombButton(PySweeperButton):
    def __init__(self, location):
        PySweeperButton.__init__(self, location)

class PySweeperBoard(Frame):
    def __init__(self, difficulty='Beginner'):
        Frame.__init__(self, bd=1)
        ...
        self.bomb_buttons = []

    ...

    def make_bombs(self):
        bombs_created = 0
        while bombs_created < self.bombs:
                col = randint(1, self.columns)
                row = randint(1, self.rows)
                loc = (col, row)
                BombButton(loc)
                self.bomb_buttons.append(BombButton)
                bombs_created += 1

    def make_bomb_indicators(self): 
        valid_location = (((range(1, self.columns)), (range(1, self.rows))))
        for bomb in self.bomb_buttons:
            adj_cells = bomb.find_adjacent_cells(bomb) # THIS IS THE LINE WHICH RAISES THE ERROR
            for cell in adj_cells:
                if cell in valid_location:
                    if self.find_oject(cell) == None:
                        BombIndicatorButton(cell)
                    else:
                        self.find_object(cell).increment_value(self.find_object(cell))

   def find_object(self, location):
            buttons = self.bomb_buttons + self.bomb_indicator_buttons + self.blank_buttons
            for button in buttons:
                if button.get_location() == location:
                   return button
            return None
...

The error reads:

File "/home/garrett/bin/pysweeperx.py", line 168, in <module>
    PySweeper = PySweeperWindow()
  File "/home/garrett/bin/pysweeperx.py", line 25, in __init__
    pysweeperboard = PySweeperBoard()
  File "/home/garrett/bin/pysweeperx.py", line 42, in __init__
    self.create_board()
  File "/home/garrett/bin/pysweeperx.py", line 60, in create_board
    self.make_bomb_indicators()
  File "/home/garrett/bin/pysweeperx.py", line 92, in make_bomb_indicators
    adj_cells = bomb.find_adjacent_cells(bomb)
  File "/home/garrett/bin/pysweeperx.py", line 130, in find_adjacent_cells
    adj_cells.append((self.col - 1, self.row -1 ))

I've omitted parts which I didn't think were relevant to the problem. If you need more code that I wrongfully excluded, just let me know. Thanks in advance.

Try taking a look at this.

class A():
    def __init__(self):
        self.var = 1

    def do_stuff_with_var(self):
        print self.var

class B(A):
    def __init__(self):
        A.__init__(self)
        self.var = A().var

    def do_stuff_with_var(self):
        A.do_stuff_with_var(self)

b1 = B()
b1.do_stuff_with_var()

I understand that I could hardcode everything. In fact, I just tried it, and I still got the error, which is very odd because I explicitly defined it in the BombButton class aka class B. This means that the problem lies elsewhere. I then proceeded by trying calling dir(bomb) on the line right before the line which raises the error. I got back a list of functions which included the ones inherited from PySweeperButton , however it did not list any of the data attributes that I intended to inherit from PySweeperButton .

The problem is the @staticmethod decorator in both of your examples. Delete that line and the first program runs OK
[plus you only supply 'instance' once, i.e.
instance.do_stuff_with_var() ].
I have not tested the second program, but that would be the place to start. Since you only have one "do_stuff_with_variables" function in the first example, and only one "find_adjacent_cells" function, @staticmethod seems unnecessary anyway. Try either example without this and if it does not do what you want, post back.

The problem is the @staticmethod decorator in both of your examples. Delete that line and the first program runs OK
[plus you only supply 'instance' once, i.e.
instance.do_stuff_with_var() ].
I have not tested the second program, but that would be the place to start. Since you only have one "do_stuff_with_variables" function in the first example, and only one "find_adjacent_cells" function, @staticmethod seems unnecessary anyway. Try either example without this and if it does not do what you want, post back.

I ran it, and I got the following error:

File "/home/garrett/bin/pysweeperx.py", line 158, in <module>
    PySweeper = PySweeperWindow()
  File "/home/garrett/bin/pysweeperx.py", line 25, in __init__
    pysweeperboard = PySweeperBoard()
  File "/home/garrett/bin/pysweeperx.py", line 42, in __init__
    self.create_board()
  File "/home/garrett/bin/pysweeperx.py", line 60, in create_board
    self.make_bomb_indicators()
  File "/home/garrett/bin/pysweeperx.py", line 91, in make_bomb_indicators
    adj_cells = bomb.find_adjacent_cells(bomb)
TypeError: unbound method find_adjacent_cells() must be called with BombButton instance as first argument (got classobj instance instead)

This was the reason I had added @staticmethod to the find_adjacent_cells(self) method. I guess here is where the true problem lies. I just need to learn how to properly call an unbound method on an instance, which I messed with earlier. I remember trying bomb.find_adjacent_cells() and that didn't work and gave me pretty much the same error saying: TypeError: unbound method find_adjacent_cells() must be called with BombButton instance as first argument (got nothing instead)

This is one error. I don't have time to dig any further now, but if there are other problems, post back.

def make_bombs(self):
        bombs_created = 0
        while bombs_created < self.bombs:
                col = randint(1, self.columns)
                row = randint(1, self.rows)
                loc = (col, row)

                BombButton(loc)
                self.bomb_buttons.append(BombButton)

                ## the above 2 lines chould either be
                self.bomb_buttons.append(BombButton(loc))
                ## or
                this_button = BombButton(loc)
                self.bomb_buttons.append(this_button)

                bombs_created += 1

Also, add some print statements to each of the classes, so you know how far you get each time.

This is one error. I don't have time to dig any further now, but if there are other problems, post back.

def make_bombs(self):
        bombs_created = 0
        while bombs_created < self.bombs:
                col = randint(1, self.columns)
                row = randint(1, self.rows)
                loc = (col, row)

                BombButton(loc)
                self.bomb_buttons.append(BombButton)

                ## the above 2 lines chould either be
                self.bomb_buttons.append(BombButton(loc))
                ## or
                this_button = BombButton(loc)
                self.bomb_buttons.append(this_button)

                bombs_created += 1

Also, add some print statements to each of the classes, so you know how far you get each time.

Thank you. This seems to have solved my problem. Marking thread as solved.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.