Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Field inheritance access in python

I have an issue with inheritance.

This is my main program:

def main(argv):
  rfp = reqboxfileparserng() # Inherits from reqboxfileparser()
  rfp.importsdir = './data/'
  if rfp.parsingasutf8_win():
    rfp.parsefile("./data/LRCv12.txt")

Here are the classes:

class reqboxfileparser():
  def __init__(self):
    ... removed code ...
    # Init mmap
    self.file = None
    self.f = None

  def parsefile(self, filename):
    # Public
    self.filename = filename

    # Init mmap
    self.file = codecs.open(filename, encoding='utf-8', mode='r') # open(filename, 'r')
    self.f = mmap.mmap(self.file.fileno(), 0, access=mmap.ACCESS_READ)
    self.f.seek(0) # rewind

    # Parsing stuff
    self.getfunlist()
    self.vlog(VERB_MED, "len(fun) = %d" % (len(self.funlist)))
    self.getfundict()
    self.vlog(VERB_MED, "fundict = %s" % (self.fundict))
... rest of reqboxfileparser() class code removed ...

class reqboxfileparserng(reqboxfileparser, object):
  def __init__(self):
    # Public
    reqboxfileparser.__init__(self)
    self.fundict = {}
    self.importsdir = ''

  def getfunlist(self):
    """
    Overrided method to load from a CSV file
    """
    self.funlist = []

    fh = open(self.importsdir + 'in-uc-objects.csv', 'rb')
    f = csv.reader(fh, delimiter=',')
  ... rest of the code removed, it works fine ...

  def getfundict(self):
    """
    Fills the fundict property with a dict where each element is indexed
    by the fun name and each value is an object from the model
    """
    self.__fundict = {}

    beginloc = self.bodystartloc()

    # PROBLEM!

    finalloc = super(reqboxfileparser, self).f.size() - 1
    ... rest of the code removed ...

As you can see I have two classes, the first is reqboxfileparser() and the second one is reqboxfileparserng() which inherits from the first one.

On the main program I call the method: parsefile("./data/LRCv12.txt") [not overrided] which later calls getfundict() [overrided] on the second class, but when I try to access f.size() it always fails with TypeError: must be type, not classobj.

It's been a while since I don't develop classes with inheritance but if I'm not wrong the concepts are right. I'm newbie to Python.

Any help please?

Thanks a lot.

like image 249
Albert Vonpupp Avatar asked Aug 04 '26 06:08

Albert Vonpupp


2 Answers

There are two issues at hand here:

Super and old-style classes:

class reqboxfileparser(): does not inherit from object, as a consequence, super(reqboxfileparser, self) will always yield the error:

TypeError: must be type, not classobj.

Improper super call in inheriting classes:

You're doing super(reqboxfileparser, self), but you're passing the inherited class (reqboxfileparser) as first argument, not the inheriting class.

As a consequence, Python would try to find a class that reqboxfileparser inherits from which implements what you're looking for you're looking for: f.

But that's not want you want: what you want an ancestor of reqboxfileparserng that implements f; that would be reqboxfileparser.

Please have a look at the documentation for the most common super call syntax.

Your solution

You probably guessed by now that you should be using super(reqboxfileparserng, self) instead.

Plus, you should always be using new-style classes (But that alone wouldn't solve your issue, you would get a different error complaining thatAttributeError: 'super' object has no attribute 'f', which would be True, as object does not provide f).

One last thing...

But here, you have one last issue!

You're trying to refer to f which is an attribute of the instance of the child class. This attribute is not present when you use the super call as it's not present in the class definition of the parent, which is the one the super call will use. (It's in the __init__ method)

I won't go into much more detail as to why this matters for super, but the idea is to basically use super only for stuff defined at class-level. Usually, methods are, so they're great candidates for super calls.

Here's an example describing what I mean:

class reqboxfileparser():
    g = 'THIS IS G'

    def __init__(self):
        self.f = 'THIS IS F'
        self.g = 'THIS IS NEW G'

    def get_g(self):
        return self.g

class reqboxfileparserng(reqboxfileparser, object):
    def __init__(self):
        reqboxfileparser.__init__(self)


    def getfundict(self):
        print super(reqboxfileparserng, self).g # Prints "THIS IS G"
        print super(reqboxfileparserng, self).get_g() # Prints "THIS IS NEW G"
        print super(reqboxfileparserng, self).f # This raises an AttributeError

if __name__ == '__main__':
    o = reqboxfileparserng()
    o.getfundict()

Overall, a super call is pretty similar to using ParentClass.stuff, only it deals with multiple inheritance better, and should be used for this reason.

You can see that here, reqboxfileparser.f would raise an AttributeError.


Footnote: a classobj is an old-style class, a type is a new-style class.

like image 181
Thomas Orozco Avatar answered Aug 05 '26 20:08

Thomas Orozco


The point you're missing is that f is an attribute of the current class. It's inherited: when you call super(...).__init__(), the code sets f on self. So to access it from the subclass, you just do self.f, just like any other attribute.

The same is true of any attribute or method. You only need to use super when your subclass has actually overridden something, and you need to call the superclass's version. So there's no need to call super to get access to parsefile, for example: self.parsefile() would do fine.

like image 38
Daniel Roseman Avatar answered Aug 05 '26 18:08

Daniel Roseman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!