real_aravind
real_aravind

Reputation: 99

Composition versus subclass for Pandas DataFrame

I am trying to create a method called 'tilt' in a Python class which turns the DataFrame upside down using Pandas. But I am getting this error "The object has no attribute 'iloc'", whenever I use this 'tilt' method on an instance created out of this class.

import numpy as np
import pandas as pd

class Board():

    def __init__(self):
        pass

    def arrange(self):

        board=pd.DataFrame(np.arange(1,65).reshape(8,8),index=[1,2,3,4,5,6,7,8],columns=[1,2,3,4,5,6,7,8])
        self = board.copy()
        self.loc[1]=['BP1','BP2','BP3','BP4','BP5','BP6','BP7','BP8']
        self.loc[2]=['blR','blK','blB','bQ','bK','brB','brK','brR']
        self.loc[7]=['wlR','wlK','wlB','wK','wQ','wrB','wrK','wrR']
        self.loc[8]=['WP1','WP2','WP3','WP4','WP5','WP6','WP7','WP8']
        print(self)

    def tilt(self):
        self.iloc[::-1]
        print(self)

Upvotes: 2

Views: 849

Answers (1)

Brad Solomon
Brad Solomon

Reputation: 40878

In .tilt(), you use self.iloc[::-1]. However, inside the scope of this instance method, self is just a plain, minimalistic Python class, not a DataFrame. It knows nothing about the operations that you did to the local variable self inside of .arrange().

Even if you call b.arrange() first, this does not modify the class instance inplace; it modifies a local copy of a variable called self inside the scope of .arrange(). That is:

>>> b = Board()
>>> b.arrange()
# ...
>>> isinstance(b, pd.DataFrame)
False

Have a look at the guide to subclassing Pandas data structures. I would recommend using composition, since actually subclassing of Pandas objects can get hairy quickly.

Here is an example of what composition would look like:

class Board(object):

    def __init__(self):
        self.board = pd.DataFrame(np.arange(1, 65).reshape(8, 8),
                                  index=np.arange(1, 9),
                                  columns=np.arange(1, 9))

    def arrange(self):
        self.board.loc[1] = ['BP1','BP2','BP3','BP4','BP5','BP6','BP7','BP8']
        self.board.loc[2] = ['blR','blK','blB','bQ','bK','brB','brK','brR']
        self.board.loc[7] = ['wlR','wlK','wlB','wK','wQ','wrB','wrK','wrR']
        self.board.loc[8] = ['WP1','WP2','WP3','WP4','WP5','WP6','WP7','WP8']
        return self.board

    def tilt(self):
        return self.board.iloc[::-1]

Usage:

>>> b = Board()
>>> b.arrange()
     1    2    3    4    5    6    7    8
1  BP1  BP2  BP3  BP4  BP5  BP6  BP7  BP8
2  blR  blK  blB   bQ   bK  brB  brK  brR
3   17   18   19   20   21   22   23   24
4   25   26   27   28   29   30   31   32
5   33   34   35   36   37   38   39   40
6   41   42   43   44   45   46   47   48
7  wlR  wlK  wlB   wK   wQ  wrB  wrK  wrR
8  WP1  WP2  WP3  WP4  WP5  WP6  WP7  WP8
>>> b.tilt()
     1    2    3    4    5    6    7    8
8  WP1  WP2  WP3  WP4  WP5  WP6  WP7  WP8
7  wlR  wlK  wlB   wK   wQ  wrB  wrK  wrR
6   41   42   43   44   45   46   47   48
5   33   34   35   36   37   38   39   40
4   25   26   27   28   29   30   31   32
3   17   18   19   20   21   22   23   24
2  blR  blK  blB   bQ   bK  brB  brK  brR
1  BP1  BP2  BP3  BP4  BP5  BP6  BP7  BP8

Upvotes: 6

Related Questions