user9448725
user9448725

Reputation:

Functions of nested class thinks 'self' as an argument - Python

I'm trying to make a game of tic-tac-toe.

I have one class, Player, and one nested class, Check, in it.

This is my full code:

class Player: # Player class
'''this is a class for the player in a tic-tac-toe game'''

def __init__(self, counter): # initialize
    self.counter = counter # set player counter

def place(self, x, y): # functions directly interfering with data can global
    '''this function helps with placing counters on the grid'''
    global grid
    grid[y][x] = self.counter

class Check:
    '''checks if a player wins or loses'''

    def check_vertical(self, grid): # checking functions avoid globaling
        '''check if there are three counters in a row vertically'''
        for row in range(3):
            if grid[row][0] and grid[row][1]\
               and grid[row][2] == self.counter:
                return True

    def check_horiontal(self, grid): # checking functions avoid globaling
        '''check if there are three counters in a row horizontally'''
        for column in range(3):
            if grid[0][column] and grid[1][column]\
               and grid[2][column] == self.counter:
                return True

    def check_diagonal(self, grid): # checking functions avoid globaling
        '''check if there are three counters in a row diagonally'''
        if grid[0][0] and grid[1][1] and grid[2][2] or\
           grid[0][2] and grid[1][1] and grid[2][0] == self.counter:
            return True

    def check_all(self, grid):
        '''check if there are three counters in a row in any direction'''
        return (self.check_vertical(self, grid) or\
                self.check_horizontal(self, grid) or\
                self.check_diagonal(self, grid))

So, when I try to test it in the shell:

>>> player = Player("O")
>>> player.Check.check_all(tic_tac_toe_grid)

Python throws an error:

Traceback (most recent call last):
  File "<pyshell#34>", line 1, in <module>
    a.Check.check_all(grid)
TypeError: check_all() missing 1 required positional argument: 'grid'

Python thinks that self is a required argument.

What's wrong with my code?

Upvotes: 0

Views: 503

Answers (2)

abarnert
abarnert

Reputation: 365717

None of this has anything to do with Check being a nested class.

First, Python thinks that self is a required argument because it is. You explicitly declared it as a parameter:

def check_all(self, grid):

When you call methods normally, on an instance of a class, like thingy.method(foo), Python will turn that thingy into the self.

But you're not calling the method on an instance of Check, you're calling it on Check itself. That's legal, but unusual. And when you do it, you need to explicitly pass an instance to be the self.

And there's your real problem—you don't even have an instance. And presumably you created the class, with attributes and an __init__ method and everything, because you needed instances of that class. (If you don't need a class, then you should get rid of the class and just make the functions methods of Player, or top-level functions.)

So, just getting rid of this error is easy:

player.Check().check_all(tic_tac_toe_grid)

But what you almost certainly want to do is to create a Check() instance somewhere that you can use when you need it. Does each Player own a single Check? Then something like this:

class Player:
    def __init__(self, counter): # initialize
        self.counter = counter # set player counter
        self.check = Check()

And then you can use it:

player.check.check_all(tic_tac_toe_grid)

I don't actually know if that's what your object model is supposed to be, but hopefully you do.

Upvotes: 2

Hugo G
Hugo G

Reputation: 16496

Check is a nested class in Player and you can access it using Player.Check or using Player instances - in your case player.

A nested class behaves just the same as a normal class. Its methods still require an instance. The self parameter to the method tells you that it operates on instances. If you don't need any state on that class, you have two options:

  1. Move all methods from Check to its own module and place the functions in there without any class. Or...
  2. Make all methods in Check static (@staticmethod). This is rather an antipattern though.

Upvotes: 0

Related Questions