I have a class Parent
with many instance properties, and I always pass a dict
to initialize an instance. Like this:
info = {
"name" : "Bob",
"col" : 5,
"line" : 10,
"type" : "Alien"
}
p = Parent(info)
And in __init__
method I don't want to write this.property_name = value
for each property cuz the code will be very long. For instance:
class Parent(object):
def __init__(self, kwargs):
this.name = kwargs.get("name")
this.col = kwargs.get("col")
this.line = kwargs.get("line")
this.type = kwargs.get("type")
So I want to use a function to iterate the dict
to set these instance properties. This is the function I wrote:
def initialize_properties(instance, names, kwargs):
for name in names:
setattr(instance, name, kwargs.get(name))
It seems that I need to store the property name list names
somewhere, and I decide to store it as a class attribute, because I want my class to be human friendly (when somebody reads the class definition he knows what instance properties this class has). So I changed my class definition as follows:
class Parent(object):
props = ("name", "col", "line", "type")
def __init__(self, kwargs):
initialize_properties(self, self.props, kwargs)
This works fine when inheritance is NOT considered. The problem occurs when I subclass Parent
:
class Child(Parent):
props = ("foo", "bar")
def __init__(self, kwargs):
super().__init__(kwargs)
initialize_properties(self, self.props, kwargs)
I want instances of Child
to inherit all the instance properties in superclass Parent
, with some child-specific instance properties as well.(This is why we use inheritance, isn't it?) So I overwrite the class attribute props
to define child-specific properties.
But it doesn't work.
info = {
"name" : "Bob",
"col" : 5,
"line" : 10,
"type" : "Alien",
"foo" : 5,
"bar" : 10
}
c = Child(info)
Instance c
only has c.foo
and c.bar
defined and set, while c.name
is not defined.
After some digging I found that when Parent.__init__(self, kwargs)
is called through the super()
function, the self
argument passed is of class Child
, so self.props
evaluates to Child.props
.
If I want to set the instance properties in Parent.props
, I have to explicitly use Parent.props
in Parent.__init__(self, kwargs)
, which is:
class Parent(object):
props = ("name", "col", "line", "type")
def __init__(self, kwargs):
initialize_properties(self, Parent.props, kwargs)
This will solve the problem, but I think it's not very "clean" because you have to hard-code the class name Parent
.
So my question is: Is there any way to detect the current class and access its class attributes, when you are calling a chain of super().__init__()
to initialize an subclass instance?
__init__() Call in Python. When you initialize a child class in Python, you can call the super(). __init__() method. This initializes the parent class object into the child class. In addition to this, you can add child-specific information to the child object as well.
The super() function is used to give access to methods and properties of a parent or sibling class. The super() function returns an object that represents the parent class.
Using Super(): Python super() function provides us the facility to refer to the parent class explicitly. It is basically useful where we have to call superclass functions. It returns the proxy object that allows us to refer parent class by 'super'.
Accessing Parent Class Functions This is really simple, you just have to call the constructor of parent class inside the constructor of child class and then the object of a child class can access the methods and attributes of the parent class.
You could implement a method that collects the props
from all supeclasses and use it in the __init__
:
class Parent(object):
props = ("name", "col", "line", "type")
def __init__(self, **kwargs):
def __init__(self, kwargs):
initialize_properties(self, self.get_props(), kwargs)
def get_props(self):
return sum((getattr(k, 'props', ()) for k in self.__class__.mro()), ())
Now, you can simply define subclasses the way you wanted. You wouldn't even have to override the constructor:
class Child(Parent):
props = ("foo", "bar")
That being said, you claim you want your classes human friendly. If a human reads your child class, they will be glad to read:
class Child(Parent):
props = 'foo', 'bar', 'name', 'col', 'line', 'type'
and have all the class' props
available in one place.
self.props
first references instance attribute, then class attribute, and parents' class attribute, ...
By defining Child.props
, self.props
refers Child.props
class attribute, stopping there, not searching in parent class.
How about make the Child.props
also include parents' props
?
class Child(Parent):
props = Parent.props + ("foo", "bar") # <---
def __init__(self, kwargs):
super().__init__(kwargs)
initialize_properties(self, self.props, kwargs)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With