简体   繁体   中英

Get attribute from a super class in python

I have a base class, a bunch of subclasses, and for each of these subclasses, I have another set of sub-subclasses. For example:

class BaseClass(object):
    def __init__(self):
        with open(config.txt) as f
            self.config_array = f.readlines()

class FirstOrderSubClass(BaseClass):
    def __init__(self, name):
        self.name = name

class SecondOrderSubClass(FirstOrderSubClass):
    def __init__(self, name, version):
        self.name = name
        self.version = version
        super(SecondOrderSubClass, self).__init__(self.name)
        # needed to access self.config_array
        print self.config_array

I need to get the __init__() method of the SecondOrderSubClass to make the following assignment: self.lines = self.config_array .

EDIT: added line print self.config_array . If I run the code I get:

TypeError: __getattr__() takes exactly 1 argument (2 given)

You cannot access self.config_array until BaseClass.__init__() has run to set the attribute.

Either fix FirstOrderSubClass to also invoke the base class __init__ or call it directly.

Fixing the FirstOrderSubClass is probably the best way to do so:

class FirstOrderSubClass(BaseClass):
    def __init__(self, name):
        super(FirstOrderSubClass, self).__init__()
        self.name = name

However, your __init__ method signatures do not match so you cannot rely on cooperative behaviour here; as soon as you add a mix-in class in the hierarchy, things can and probably will break. See *Python's super() is considered super! by Raymond Hettinger, or it's followup PyCon presentation to explain why you want your signatures to match.

Calling the BaseClass.__init__ unbound method directly (passing in self explicitly) would also work:

class SecondOrderSubClass(FirstOrderSubClass):
    def __init__(self, name, version):
        super(SecondOrderSubClass, self).__init__(name)
        self.version = version
        BaseClass.__init__(self)

Note that there is no point in assigning to self.name there if you are going to ask FirstOrderSubClass.__init__ to do the exact same thing.

The proper way to use super() is for all your methods to at least accept all the same arguments. Since object.__init__() never does, this means you need a sentinel class that does not use super() ; BaseClass will do nicely here. You can use *args and **kw to capture any additional arguments and just ignore those to make cooperative subclassing work:

class BaseClass(object):
    def __init__(self, *args, **kw):
        with open(config.txt) as f
            self.config_array = f.readlines()

class FirstOrderSubClass(BaseClass):
    def __init__(self, name, *args, **kw):
        super(FirstOrderSubClass, self).__init__(*args, **kw)
        self.name = name

class SecondOrderSubClass(FirstOrderSubClass):
    def __init__(self, name, version, *args, **kw):
        super(SecondOrderSubClass, self).__init__(name, *args, **kw)
        self.version = version

You have to call the FirstOrderSubClass super method:

class BaseClass(object):
    def __init__(self):
        with open("config.example.txt",'w') as f:
            f.write("Hello world")
        with open("config.example.txt") as f:
            self.config_array = f.readlines()

class FirstOrderSubClass(BaseClass):
    def __init__(self, name):
        super(FirstOrderSubClass,self).__init__()
        self.name = name

class SecondOrderSubClass(FirstOrderSubClass):
    def __init__(self, name, version):
        self.name = name
        self.version = version
        super(SecondOrderSubClass, self).__init__(self.name)
        # needed to access self.config_array

grandchild = SecondOrderSubClass("peter",2.0)
print grandchild.config_array
##>>> 
##['Hello world']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM