Inheriting Attributes from Classes in Python

864 views Asked by At

I need the _plot function to be able to access dataClass's .name attribute so that the graph would have the title Aluminum. However, I keep getting the error:

AttributeError: type object 'dataClass' has no attribute 'name'

How can I get _plot to inherit dataClass's .name attribute?

import matplotlib.pyplot as plt.

class dataClass(object):
    def __init__(self, name, dictionary):
        self.name = name
        self.add_model(dictionary)
    def add_model(self, dictionary):
        model_name = dictionary['model']
        setattr(self, model_name, _model(model_name)
        *there is some code here which gives real vales to model.data, model.error, and model.xaxis*

class _model(dataClass):
    def __init__(self, model_name):
        self.modelname = model_name
        self.data = None
        self.error = None
        self.xaxis = None

    def _plot(self, fig=None, ax=111, xaxis=None, **kwargs):
        if fig is None:                     # no figure given
            fig = plt.figure()
            ax = plt.subplot(ax)
        elif isinstance(ax, (int, float)):  # figure given
            ax = fig.add_subplot(ax)
        else:                               # figure and axis given
            pass
        if xaxis is None:
            xaxis = self.xaxis
        super(_model,self).__init__   # this line doesn't work
        name = dataClass.name         # this line raises the error
        name = ax.errorbar(xaxis, self.data, yerr=self.error, ls='-', label=name)
        handles, labels = ax.get_legend_handles_labels()
        ax.legend(handles, labels, loc='upper right')
        return fig

def makePlot(xAxis, thing_to_plot):
    fig, ax = plt.subplots(1, 1)
    thing_to_plot._plot(fig, ax, xAxis)
    plt.title("Measured and Best Fit Function")
    plt.savefig("lineplots2.png")
    plt.close(fig)

Dust = dataClass('Dust', {'model': 'raw', 'data': [eqn.dustRatio(const)*eqn.dust(l) for l in lDict['lList']]})
makePlot(lDict['lList'], Dust.raw)

Thanks in advance.

Edit I had found a post elsewhere on Stack Overflow which gave some suggestions for how to make objects add themselves to existing plots. I took the code and edited it to this. Now I am trying to make this practice function part of my actual code

class Plotter(object):
    def __init__(self, xval=None, yval=None):
        self.xval = xval
        self.yval = yval
        self.error = None

    def plotthing(self, fig=None, index=1):
        if fig is None:
            fig = plt.figure()
            ax = plt.subplot(111)
        else:
            ax = fig.add_subplot(2,1,index)
        name = 'curve{}'.format(1)
        name = ax.errorbar(self.xval, self.yval, yerr=self.error, ls='-', label=name)
        handles, labels = ax.get_legend_handles_labels()
        ax.legend(handles, labels, loc='upper right')
        return fig


def compareplots(*args):
    fig = plt.figure()
    for i, val in enumerate(args):
        val.plotthing(fig, i+1)
        plt.title("Measured and Best Fit Function")
    return fig

app1 = Plotter(xval=range(0,10), yval=range(0,10))
plot1 = app1.plotthing()
plot1.savefig('testlong.png')
app2 = Plotter(xval=range(0,11), yval=range(1,12))

thingummy = compareplots(app1, app2)
thingummy.savefig('test.png')
2

There are 2 answers

1
warvariuc On

I guess the exception happens on this line:

name = dataClass.name

Here you are trying to access class attribute of class dataClass which doesn't exist:

class dataClass(object):
    def __init__(self, name, dictionary):
        self.name = name
        self.add_model(dictionary)

Here you've created instance attribute, which you can access if you have the instance.

How can I get _plot to inherit dataClass's .name attribute?

_model class instances automatically inherit this attribute. I guess you meant to use name = self.name instead of name = dataClass.name, though this leaves me in doubt:

def _plot(self, fig=None, ax=111, xaxis=None, **kwargs):
    if fig is None:
        fig = plt.figure()
    super(_model,self).__init__()

You are calling parent class "constructor" from a non-constructor method.

6
Rob Foley On

There are two things (that I know of) that you could be trying to do. You could be attempting to access a class attribute, or you are trying to access an instance attribute. If you want the first, you would need your dataClass to be something like this:

class dataClass(object):
    name = 'jim'
    def __init__(self, dictionary):
        self.add_model(dictionary)
    def add_model(self, dictionary):
        model_name = dictionary['model']
        setattr(self, model_name, _model(model_name))

If you are trying to access a class attribute assigned by the setattr() in the add_model method, then you will have to access it by using dataClass."model_name" where model name is the name of the model you want to access.

If you are trying to access an instance attribute, you will have to pass an instance of the dataClass object to the _model to the method, or do something similar to that. The overall structure of your program is very confusing, as I am not really sure what objective you are trying to accomplish by accessing the attribute this way, as well as the way in which you are adding attributes to the dataClass object.

If you just want to inherit the class attribute, then you need only use the code above. I am not sure what, exactly, you mean by inherit, since it doesn't seem like inheritance is really what you are after. If you could clarify your intentions, that would be very heplful.

EDIT: After getting a better idea of what you are trying to do, I think a better way of accessing that information would be with classes like this:

class dataClass(object):
    def __init__(self, name, dictionary):
        self.name = name
        self.models = {}
        self.add_model(dictionary)

    def add_model(self, dictionary):
        model_name = dictionary['model']
        if 'data' in dictionary:
            data = dictionary['data']
        else:
            data = None
        self.models.update({model_name : data})

class model(object):
    def __init__(self, model_name):
        self.modelname = model_name

    def plot(self, thing_to_plot , fig=None, ax=111, xaxis=None, **kwargs):
        # do meaningful work here
        return thing_to_plot.name

example = dataClass('Aluminum', {'model': 'Thermal Conductivity'})
thing = model("doug")

print("Plotted object's name: %s" % thing.plot(example))
print("_model name: %s" % thing.modelname)

Hopefully that will be more useful.