0

I have an class that defines an 'alarm' and then one the defines a 'httpalarm'. Now a httpalarm shares many of the same properties as that of alarm (in fact is has all the same ones, plus others).

What I think I should be able to do is define these properties once as part of the alarm object, and then when httpalarm is created as a child of alarm, it should get all properties already. But it doesn't. At least, it doesn't appear to;

class alarm(object):
    def __init__(self, severity, name, eventId):
        self.severity = severity
        self.name = name
        self.eventId  eventId


class httpalarm(alarm):
    def __init__(self, **kwargs):
        self._dict__.update(kwargs)

Now when I create an alarm object I get what I expect:

a = alarm('Critical', 'Name', '0x800111')

vars(a)
->
{'severity': 'Critical', 'name': 'Name', 'eventId': '0x800111'}

This is as expected. However when I create a httpalarm:

b = httpalarm(test = 'Test')
vars(b)
->
{'test': 'Test'}

This is unexpected. I was anticipating that the httpalarm b, would also have a severity, name and eventId attribute already set.

So rather than instance properties, I set the alarm class to use class properties:

class alarm(object):
    severity = 'Warning'
    name = None
    eventId = None

and then again with no changed to httpalarm I tested again;

c = httpalarm(test='Test')

vars(c)
->
{'test': 'Test'}

Again, vars isn't showing all the other properties. However, they are being set as;

print c.severity
'Warning'

printing an inherited property does seem to work. And also using dir(c) to show the object does indeed return all the properties

dir(c)
-> 
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eventId', 'name', 'severity', 'test']

I'm not really sure whats going on here. I'd like to create an alarm class that I can inherit from to save me having to define out the same properties all the time. What I'm trying to get is:

d = httpalarm(severity = 'Critical', name = 'Name', eventId = '0x800111', test = 'test')

and have the httpalarm instance d include all the properties from alarm as well as the properties from its own httpalarm class.

Edit: Following the submission from Corley Brigman I've got this working working as expected using:

class httpalarm(alarm):
    def __init__(self,
                 **kwargs):

        super(httpalarm, self).__init__()
        for k,v in self.__dict__.iteritems():
            if type(v) == tuple:
                setattr(self, k, v[0])

        self.__dict__.update(kwargs)

1 Answer 1

1

You need to call alarm's constructor yourself:

class httpalarm(alarm):
    def __init__(self, **kwargs):
        super(httpalarm, self).__init__()
        # Your code here

Why is this especially required here? Python's object implementation is significantly different from other languages like C++ and Java; it has to do a lot with how objects are created.

A C++ object is basically a memory structure with some functions attached to it. A Python object is more like a dictionary with some functions attached to it. How does this play out?

In both environments, you can imagine the creation (new, but usually behind the scenes in C++; __new__ as a function of a class in Python), and initialization (the constructor in C++, and __init__ in Python) as two separate pieces.

In C++, since the memory structure is essential to the operation of the object, when you call new (at a high level) the system allocates space for each attribute that is declared with the right size. This is static - you cannot create new attributes on the fly, you can only modify the attributes you declared. Note that this also requires that when you subclass, you are also declaring exactly what the structure will look like - so the compiler can build the proper memory image.

Then, you call the constructor, which actually initializes the values based on inputs and whatever the programmer wants. In many cases, you can actually leave the constructor out in C++, or declare it but leave it empty, if you are happy with the default values that get initialized.

In Python, since the object model is more like a mutable dict, the base class behaviour ('create a dictionary and attach to the object') is to create that dictionary. This is usually sufficient for most usages, so in Python, you will hardly ever see a __new__ function written (*).

Instead, the default for most people is to initialize the variables in the __init__ function. The important thing is this is called after the object is created. You can then set whatever variables you want to whatever data (of whatever type) you want.

The critical thing is that in both cases, the object is created before calling the initializer. In C++, the creation creates the data structure. In Python, the object creation (usually) just creates a dictionary - at the entry to alarm.__init__ and httpalarm.__init__, both objects look just like an empty dictionary. The init has to create the necessary attributes. It's not unusual to call base class constructors in C++ either, but it's even more common in Python, because the base class constructors also create the common attributes used by the subclass.

You can use slots - they are closer to how C++ works, but not exactly.

For vars - vars only shows local attributes - ones you've set in __init__ or elsewhere. When you declare them as class variables, they'll show up in dir, because that shows both class attributes and locally-set object attributes, but not vars. From the docstring:

vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

Class variables are in object.__class__.__dict__ instead of object.__dict__.

If you really want that behaviour, you can actually use metaclasses, and override the __new__ functions to create some default attributes. It's not that common, but it would work more like C++ (as far as I know... i have not done that much either). But it is done sometimes (usually called 'metaprogramming' or something like that), especially if you want dynamic properties, since properties are (necessarily) a class attribute, and can't be set dynamically on an object; instead, you use a class factory, which dynamically adds the attributes required.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.