Python inner class inherit from outer - python

I have an issue with class inheritence and haven't been able to find an appropriate solution elsewhere.
I have 2 classes a Parent class and a Child class.
A Child is a type of Human so I want to use class inheritance, which normally would be straightforward we just have.
class Human:
def __init__(self,type,name): # Do this when we create a Node instance
self.type = type
self.name = name
class Child(Human):
def __init__(self,name,siblings): # Do this when we create a Node instance
super().__init__(type=Child,name=name)
self.siblings = siblings
but I want to be a pain and I want to create instances by using Human.Child(parameters) rather than Child(parameters) and I don't want to have a Child class in the main scope.
I have managed to make that work by using a classmethod but it's pretty messy. Is there a more elegant solution?
class Human:
def __init__(self,type,name): # Do this when we create a Node instance
self.type = type
self.name = name
def execute(self):
print(f"executing the Human {self.name}")
#classmethod
def Child(cls,*args,**kwargs):
class Child(cls):
def __init__(self,name,siblings):
super().__init__(type=Child,name=name)
self.siblings = siblings
def execute(self):
print(f"executing the Child {self.name}")
return(Child(*args,**kwargs))
ideally it would look something like below, but of course, we cannot pass Human to the Child class as it hasn't yet been defined.
class Human:
def __init__(self,type,name): # Do this when we create a Node instance
self.type = type
self.name = name
def execute(self):
print(f"executing the Human {self.name}")
class Child(Human):
def __init__(self,name,siblings):
super().__init__(type=Child,name=name)
self.siblings = siblings
def execute(self):
print(f"executing the Child {self.name}")

When a class definition is encountered, the class object isn't created until the entire body is read, and a full dictionary accumulated. This is the opposite of how a module object is created, where an empty module is available immediately to help avoid circular imports, among other things. That being said, nothing prevents you from modifying the attributes of a class after it is fully created.
class Human:
def __init__(self,type,name): # Do this when we create a Node instance
self.type = type
self.name = name
class Child(Human):
def __init__(self,name,siblings): # Do this when we create a Node instance
super().__init__(type=Child,name=name)
self.siblings = siblings
Human.Child = Child
del Child
A few things to keep in mind:
Passing in type is redundant. You can always access that information through the type function.
Humans tend to have siblings even after they stop being children.
While I'm the one suggesting this approach, I do not endorse it. Rather than complicating things without any need, try to keep your classes in the top level namespace.

Related

self need in call to parent class by name when using multi inheritance

Edit: Thanks for the replies. This is a practice exercise from a website that I'm using to learn, I haven't designed it. I want to confirm that the Wolf.action(self) is an static call and ask why would you make Wolf inherit from Animal if you can only use Dog Class' methods with super() due to MRO (in Diamond scheme). Is there any point on making a subclass inherit from several independent classes since you can only use super() with the first one listed in the definition? Does it have anything to do with imports?
So, in this code:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def action(self):
print("{} wags tail. Awwww".format(self.name))
class Wolf(Animal):
def action(self):
print("{} bites. OUCH!".format(self.name))
class Hybrid(Dog, Wolf):
def action(self):
super().action()
Wolf.action(self)
my_pet = Hybrid("Fluffy")
my_pet.action() # Fluffy wags tail. Awwww
# Fluffy bites. OUCH!
Why do I have to provide self in Wolf.action(self) but not in super().action()?
Why can't I just do Wolf.action()?
I'm guessing this is just an static call, and thus that's why I need to pass an explicit parameter. But then, what is the point of multi inheritance in this context? Wouldn't it be the same if Hybrid doesn't inherit from Wolf?
I've read some other threads but the majority of them talk about MRO and that is not the answer I'm looking for.
Thanks in advance.
Wolf.action is the actual function, not a bound method that implicitly includes self when you try to call it.
However, if you use super properly, you don't need an explicit call to Wolf.action.
class Animal:
def __init__(self, name):
self.name = name
def action(self):
pass
class Dog(Animal):
def action(self):
super().action()
print("{} wags tail. Awwww".format(self.name))
class Wolf(Animal):
def action(self):
super().action()
print("{} bites. OUCH!".format(self.name))
class Hybrid(Wolf, Dog):
pass
my_pet = Hybrid("Fluffy")
my_pet.action() # Fluffy wags tail. Awwww
# Fluffy bites. OUCH!

Edit parent object's attributes in a nested object

I am trying to solve a problem where I have a class which is used to store objects of other classes. I want to be able to create a list in that parent object of certain types of nested objects. (sorry if I'm phrasing this badly)
For my example I am taking a real world problem of a House. In the house we may have many different 'things'. We could have people, pets, furniture, computers etc.
I want to be able to store this in a nested format so I create a House with any of those sub-objects within.
E.g
old_rectory = House(
Person('Barry'),
Person('Bob'),
Pet('Bill'),
Pet('Brenda')
)
I have created 3 classes: the first is for the House itself, then I have a class for people and a class for pets.
For the house class I use *argv so that I can add as many other objects as necessary.
Now in the example above I would like to be able to access old_rectory.people and see a list of any instances in old_rectory that are of the type Person.
class House:
def __init__(self,*argv):
self.people = []
self.pets = []
for arg in argv:
if isinstance(arg, Person):
self.people.append(arg)
elif isinstance(arg, Pet):
self.pets.append(arg)
class Person:
def __init__(self,name):
self.name = name
class Pet:
def __init__(self,name):
self.name = name
You can see that I have achieved this by hard coding the lists and some if conditions into the House class. But this means that whenever I create a new class I also need to add in a new list and the logic to the House class.
I would like to be able to access the house object's attributes from the individual classes (Person, Pet, etc.) but I am unsure of how to proceed or if it is even possible.
class Doors:
NOW CREATE THE NEW LIST IN HOUSE CLASS
def __init__(self,name):
self.name = name
NOW APPEND THIS OBJECT TO THE NEW LIST IN THE HOUSE CLASS
I can see two clear patterns on how to try to overcome this:
Create methods for getting the instances of a specific class
Simply put every instance inside a big list and add methods to get each "sublist":
class House:
def __init__(self,*argv):
self.things = [*argv]
#property
def pets(self):
return [thing for thing in self.things if isinstance(thing, Pet)]
#property
def people(self):
return [thing for thing in self.things if isinstance(thing, Person)]
This doesn't really solve your initial problem, but at least it's easier and cleaner to implement for new classes - if a list attribute does not exist, it's because you haven't implemented the method for it.
Use hasattr, setattr and getattr
Use these functions on the __init__ method to programatically check if each list exists, create them if needed and append each instance to the corresponding list:
class House:
def __init__(self,*argv):
for arg in argv:
name = arg.__class__.__name__.lower()
if not hasattr(self, name):
setattr(self, name, [])
getattr(self, name).append(arg)
I personally think this is worse, since your attributes will be named exactly like the class name (i.e. person, not people), and you can't clearly see which lists are initialized as attributes or not since it's done on the fly, but it should work for your described use case.
Whichever way you decide to go with, note that I personally feel like your design isn't very effective for dealing with this problem. I'd rather create empty lists for people, pets etc on the House's __init__ method and add specific methods like add_person, add_pet, add_group etc for appending objects to the House's list attributes. It may not seem like much, but this design:
a) clearly defines supported classes that can interact with the House class; and
b) lets you see more clearly exactly who is getting put into the House, since you need to explicitly call the method in order to do so.
I have restructured your code. Check it out :)
class House:
def __init__(self,*argv):
self.house_classes = {"people": Person, "pets": Pet}
self.house_objects = {}
for object in argv:
self.add_house_object(object)
def add_house_class(self, class_id, class):
self.house_classes["class_id"] = class
def add_house_object(self, object):
for class_id in self.house_classes:
if isinstance(object, self.house_classes[class_id]):
if class_id in self.house_objects:
self.house_objects["class_name"].append(object)
return
self.house_objects["class_id"] = [object]
class Person:
def __init__(self,name):
self.name = name
class Pet:
def __init__(self,name):
self.name = name
To add new classes (e.g Doors) to a house object (as i think you want)
my_house = House(house_objects...) #initialise a house object
class Doors: #your new class to add to house object
def __init__(self,name):
self.name = name
my_house.add_house_class(self, "doors", Doors) #added to house object
new_door = Door("my door") #door object
my_house.add_house_object(new_door)
I hope that helps :)
You can check if House has a doors list with getattr(House, 'doors', None) and create the list if it is not existing. This solution assumes that you intend to create the list as a class variable (I am assuming this, since you do NOT pass any House-instance reference do Doors when instantiating a Doors instance).
class Doors:
def __init__(self,name):
if getattr(House, 'doors', None) is None:
House.doors = []
self.name = name
House.doors.append(self)
BUT I strongly advise you to NOT USE THIS PATTERN. This looks like a good case for class inheritance, for example creating the class Doors with class Doors(House):.
Furthermore I've got the feeling that you should take a look at the definitions and meanings of class variables and instance variables.
Imho the best way to deal with this task would be to make Doors a class which inherits from House and to require an existing instance of house to be able to create a Doors instance (for example check with if isinstance(new_house, House):). Then the Doors __init__ method could create and/or append a list doors as instance variable to House.
This way you can create many different houses. Whereas when using a class variable for the doors list, each house would have all doors created in all houses.
Thus I recommend using this pattern:
class Doors(House):
def __init__(self, name, house):
if not isinstance(house, House):
raise ValueError('`house` is not an existing instance of the `House` class')
if getattr(house, 'doors', None) is None:
house.doors = []
else:
print('exi')
self.name = name
house.doors.append(self)
As jfaccioni pointed out: Inheritance is not mandatory here, but this kind of construct looks like you are going to need it in the long term for method-access etc.

Is it acceptable to initialize the parent class from within the subclass __init__()?

Is it good practice to initialize a parent class from within the subclass, so that the parent class attributes are available to the created subclass instance?
Are there alternatives or best practices in doing so?
As an example:
class Animal(object):
def __init__(self, name, weight, cute=False, image=None):
#Instantiation attributes
self.name = name
self.weight = weight
self.cute = cute
self.image = image
#Attributes common to all animals
self.extinct = False
def get_animal_stats(self):
print arbitrary_animal_stat
class Dog(Animal):
def __init__(self, name, weight):
Animal.__init__(self, name, weight, cute=True, image="dog.com")
#Additional attributes unique to dogs
self.number_legs = 4
self.teeth = True
def make_noise(self):
print "Bark!"
As I understand it, without initializing the parent class during the subclass initialization, the subclass object only has access to its own attributes (ie. number_legs and teeth, and make_noise) and not the parent classes attributes or methods (ie. extinct, and get_animal_stats).
I find myself writing many small classes for predefined objects but have to initialize the parent with the child. In this way, I can create a simple Animal on the fly or create a more descriptive Animal through the Dog subclass.
What is the proper way to access Parent attributes and methods from the subclass instance? Am I misunderstanding the use of subclasses?
Not only is it acceptable, you should almost always call the parent class's constructor. The only reason you would not do so is if you
are absolutely sure that there will never be any initialization code defined in the parent class that is necessary for the object to function and
You want to explicitly override the parent class's initialization behavior.
With new style classes (those that inherit from object), it is better to use super() as it takes care of resolution order in cases of multiple inheritance. In Python 2.7, use:
class ParentFooA(GrandparentFoo):
def __init__(self):
some_important_initialization_code()
class ChildFoo(ParentFoo):
def __init__(self):
super(ChildFoo, self).__init__()
Note that another nice property is that you don't have to use the name ParentFoo anywhere in ChildFoo except when you define inheritance (for instance, in the line class ChildFoo(...)). It also works for other methods:
class ChildFoo(ParentFoo):
...
def do_buzz(self):
super(ChildFoo, self).do_buzz()
super() does not work for old-style classes (that is, classes that don't inherit from object).
This means that with much of the standard library, you still have to call the parent class's constructor explicitly. So in this case:
class OldStyleParent:
def __init__(self):
...
You would have to call OldStyleParent.__init__() explicitly in __init__().
In Python 3, super's syntax is simply:
class ChildFooInPython3(ParentFoo):
def __init__(self):
super().__init__()
Nothing wrong with that, although you might want to use super():
super(Dog, self).__init__...
Or in Python 3:
super().__init__...
class Dog(Animal):
def __init__(self, name, weight):
super(Dog, self).__init__(name, weight, cute=True, image="dog.com")
#Additional attributes unique to dogs
self.number_legs = 4
self.teeth = True
def make_noise(self):
print "Bark!"

special handling of a list attributes in interdependent classes in python

I'm defining some objects that essentially have list attributes that can point to each other. For instance,
class Child(object):
def __init__(self, parents=[]):
self.name = name
self.parents = parents
class Parent(object):
def __init__(self, children=[]):
self.name = name
self.children = children
Being relatively new to python, I'm wondering if there's an elegant way of ensuring that when a parent is added to a child's parents list, the child is automatically added to the parent's children list. Similarly when I remove a parent from a child's parents list, the child reference should be removed from the children attribute of the parent.
So far I've resorted to special methods to add and remove instances of the other class type.
For instance,
class Child(object):
def __init__(self, parents=[]):
self.name = name
self.parents = parents
def addParent(self, parent):
if isinstance(parent, Parent) and parent not in self.parents:
if self not in parent.children:
parent.children.append(self)
self.parents.append(parent)
etc..
It's working, but I'm hoping that I can possibly subclass the list object and manage this under the hood so that, a) someone unfamiliar with the object can simply use the standard list methods on the attribute without worrying about these special class dependencies, and b) i can learn how to emulate a container type.
I read another post about subclassing the list type, albeit for a more complex situation with mutating attributes and callbacks.
How to handle innerclass attribute dependencies?
Would this be a good starting point or am I better off simply creating methods as shown above to add, remove to respective list attributes?
EDIT:
To be clear, I'm not a programmer, so what may seem obvious in your comments is not necessarily the case to me. I'm researching and appreciate the feedback.
With the example above I tried sub-classing list:
class LinkedParentList(list):
def __init__(self, container=None):
super(LinkedParentList, self).__init__(self)
self._container = container
def __setitem__(self, index, value):
if self._container not in value.children:
value.children.append(self._container)
print 'Adding to LinkedParentList'
super(LinkedParentList, self).__setitem__(index, value)
def __delitem__(self, index):
item = self.__getitem__(index)
if self._container in item.children:
item.children.remove(self._container)
super(LinkedParentList, self).__delitem__(index)
And in my original Child class:
class Child(object):
def __init__(self, parents=None):
self.name = name
self.parents = LinkedParentList(self)
This however doesn't seem to work, in fact the setitem and delitem are not printing. Should I instead be overriding append, remove directly?

Nested Python class needs to access variable in enclosing class

I've seen a few "solutions" to this, but the solution every time seems to be "Don't use nested classes, define the classes outside and then use them normally". I don't like that answer, because it ignores the primary reason I chose nested classes, which is, to have a pool of constants (associated with the base class) accessible to all sub-class instances which are created.
Here is example code:
class ParentClass:
constant_pool = []
children = []
def __init__(self, stream):
self.constant_pool = ConstantPool(stream)
child_count = stream.read_ui16()
for i in range(0, child_count):
children.append(ChildClass(stream))
class ChildClass:
name = None
def __init__(self, stream):
idx = stream.read_ui16()
self.name = constant_pool[idx]
All classes are passed a single param, which is a custom bitstream class. My intention is to have a solution that does not require me to read the idx value for ChildClass while still in the ParentClass. All child-class stream reading should be done in the child class.
This example is over simplified. The constant pool is not the only variable i need available to all subclasses. The idx variable is not the only thing read from the stream reader.
Is this even possible in python? Is there no way to access the parent's information?
Despite my "bit patronizing" comment (fair play to call it that!), there are actually ways to achieve what you want: a different avenue of inheritance. A couple:
Write a decorator that introspects a class just after it's declared, finds inner classes, and copies attributes from the outer class into them.
Do the same thing with a metaclass.
Here's the decorator approach, since it's the most straightforward:
def matryoshka(cls):
# get types of classes
class classtypes:
pass
classtypes = (type, type(classtypes))
# get names of all public names in outer class
directory = [n for n in dir(cls) if not n.startswith("_")]
# get names of all non-callable attributes of outer class
attributes = [n for n in directory if not callable(getattr(cls, n))]
# get names of all inner classes
innerclasses = [n for n in directory if isinstance(getattr(cls, n), classtypes)]
# copy attributes from outer to inner classes (don't overwrite)
for c in innerclasses:
c = getattr(cls, c)
for a in attributes:
if not hasattr(c, a):
setattr(c, a, getattr(cls, a))
return cls
Here is a simple example of its use:
#matryoshka
class outer(object):
answer = 42
class inner(object):
def __call__(self):
print self.answer
outer.inner()() # 42
However, I can't help but think some of the ideas suggested in other answers would serve you better.
You don't need two classes here. Here's your example code written in a more concise fashion.
class ChildClass:
def __init__(self, stream):
idx = stream.read_ui16()
self.name = self.constant_pool[idx]
def makeChildren(stream):
ChildClass.constant_pool = ConstantPool(stream)
return [ChildClass(stream) for i in range(stream.read_ui16())]
Welcome to Python. Classes are mutable at runtime. Enjoy.
You can access the parent class through its name:
class ChildClass:
name = None
def __init__(self, stream):
idx = stream.read_ui16()
self.name = ParentClass.constant_pool[idx]
Then again, I'm not sure I understand what you are trying to achieve.
Another alternative design to consider:
When you find yourself trying to use classes as namespaces, it might make more sense to put the inner classes into a module of their own and make what were the attributes of the outer class global variables. In other words, if you never intend to instantiate your ParentClass, then it's just serving as a glorified module.
Global variables get a bad rap in most programming languages, but they are not truly global in Python, and are nicely encapsulated to the module.
Well, the following works (further simplified from your example). Note that you don't have to "declare" member variables at class level like C++/C#/Java etc, just set them on self within __init__:
class ParentClass:
def __init__(self):
self.constant_pool = ["test"]
self.ChildClass.constant_pool = self.constant_pool
self.children = [self.ChildClass()]
class ChildClass:
def __init__(self):
self.name = self.constant_pool[0]
print "child name is", self.name
p = ParentClass() # Prints "child name is test"
Note that you could still do the same sort of thing without the child classes being nested.
Your question uses the word subclass, so I'm keying from that to interpret your question. As with the others who have answered, I am not certain I understand what you are looking for.
class ParentClass(object):
constant_pool = [c1, c2, c3]
def __init__(self):
# anything not included in your question
class ChildClass(ParentClass):
def __init__(self, stream):
ParentClass.__init__(self)
self.name = ParentClass.constant_pool[stream.read_ui16()]
stream = get_new_stream()
children = []
for count in range(stream.read_ui16()):
children.append(ChildClass(stream))
This code uses inheritance to derive ChildClass from ParentClass (and all methods, etc). The constant_pool is an attribute of ParentClass itself, though it is OK to treat as an attribute of any instance of ParentClass or ChildClass (saying self.constant_pool within ChildClass.__init__ would be equivalent to the above but, in my view, misleading).
Nesting the class definitions is not necessary. Nesting the definition of ChildClass within ParentClass just means that ChildClass is an attribute of ParentClass, nothing more. It does not make instances of ChildClass inherit anything from ParentClass.

Categories

Resources