rationale behind python class/subclass inheritance - python

When I create a parent class and child class as shown below, why don't the arguments from the parent class automatically get pulled in by the child class?
I understand that explicit is better, but I'm wondering in what circumstance this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testParentParam1,testParentParam2,testChildParam1,testChildParam2):
pass
Is better than this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testChildParam1,testChildParam2):
pass

Derived classes extend base classes. That means they might need more/less/different information at construction time to do their extending. Consider:
class BaseTextDocument(object):
def __init__(self, content):
self.content = content
class WordDocument(object):
def __init__(self, path, word_version="guess_from_file"):
content = parse_word_document(path, word_version)
super(WordDocument, self).__init__(content)

Related

Limit access to a class function to child classes that inherit from the class

I have a use case where there are some attributes that are common to different categories that I capture through a base class and then there are some category specific parameters that are assigned in the child class definitions. For example,
class Parent:
def __init__(self):
self.category_param = None
def run_category(self):
self.category_param.run()
class Child(Parent):
def __init__(self, cat_param):
super(Child, self).__init__()
self.category_param = cat_param
Although the function run_category has the same form for all instantiations of class Child, it does use a category specific param that is None/undefined in class Parent.
I am looking for a clean way to prevent being able to call run_category() from an instantiation of class Parent.
parent = Parent()
parent.run() # Should throw an error
I would like the above code to throw an error message that I have control over (since the error message None has no attribute run() is undesirable and would be the current way the above code crashes).
A possibility is of course to define run_category as,
def run_category(self):
if self.category_param is not None:
self.category_param.run()
else:
raise NotImplementedError("method run() is not available for abstract base class Parent")
but I was looking for something cleaner/more pythonic.

How does this python inheritance hierarchy work? (specific example)

I am working on a code base that uses oop and I am relavtively new to it. My question specifically is, why NewMenuItem not inherit from File?
code bunk to play with code: https://codebunk.com/b/350127244/
"""Build class hierarchy and get values from decendants"""
import inspect
def selftest():
class Menu(object):
def __init__(self):
super(Menu, self).__init__()
self.value = "Menu"
class MenuBar(Menu):
#having object in there makes it a new style object, which allows us to use super
def __init__(self):
super(MenuBar, self).__init__()
self.value = "MenuBar"
class File(MenuBar):
def __init__(self):
Menu.__init__()
super(File, self).__init__()
self.value = "File"
self.FileValue = "File here!"
class New(Menu):
def __init__(self):
Menu.__init__()
pass
class NewMenuItem(Menu):
def __init__(self):
"""
Q 1- Why do I need self here?
Menu.__init__(self)
"""
Menu.__init__(self)
pass
def show_vals(self):
print(self.value)
"""
Q 2 -why wont this work?
def show_vals2(self):
print(self.FileValue)
"""
example = File.New.NewMenuItem()
example.show_vals()
"""
Q 3 - Why do I get this error with this line?
inspect.getmro(example)
AttributeError: 'ManageProduct' object has no attribute '__bases__'
"""
I'm trying to understand what is happening line by line, but what I don't get is why NewMenuItem doesn't inherit from File.
I tried hard-coding the instantiation of File,like so:
File.init()
but then I get an error unless I pass the File object:
File.__init__(File())
I guess what I am struggling with is:
-inheritance trees
-super classes
-why we need to hard-code instantiations in this case
Keep in mind that this is the code I have come across. I am not sure why this is the way it is.
Inheritance and scope are two completely different things. NewMenuItem is defined inside the scope of the class New, inside of the scope of the class File, but it inherits from Menu, which inherits from object. So while NewMenuItem will only be accessible through the class File and again through New, it will inherit its methods from Menu, and super will refer to Menu.

Inheritance and initialization of attributes

class Email():
def __init__(self, store_number):
self.store_number = store_number
def amethod(self):
pass
What is the correct way to pass variables from a sub-class to a parent-class?
should I do:
class MoreSpecificEmail():
def __init__(self, store_number):
Email.__init__(self, store_number=store_number)
def another_method(self):
pass
or:
class MoreSpecificEmail():
def __init__(self, store_number):
self.store_number = store_number
Email.__init__(self, store_number=self.store_number)
I have just been using different abbreviations of store_number in each sub-class to help clarify what's going on in my head. I am sure that is the wrong way, though.
What you currently have isn't inheritance; neither of your classes actually inherits from anything! Firstly, Email should be a "new-style class", inheriting from object:
class Email(object):
# ^ note inheritance from object
def __init__(self, store_number):
self.store_number = store_number
def amethod(self):
pass
Then MoreSpecificEmail should inherit from Email - as it doesn't have any additional instantiation parameters, it can just use the inherited __init__ and doesn't need to define its own:
class MoreSpecificEmail(Email):
# ^ note inheritance from Email
# note no need to define __init__
def another_method(self):
pass
For an example where there are additional __init__ parameters, note that you should use super and rely on the superclass's __init__ to assign the parameters it takes - you only need to assign the attributes that don't get handled by the superclass:
class MoreSpecificEmail(Email):
def __init__(self, store_number, something_else):
super(MoreSpecificEmail, self).__init__(store_number)
# ^ pass it straight on
self.something_else = something_else
def another_method(self):
pass
For more information, see the Python class tutorial.

Subclassing a Python class to inherit attributes of super class

I'm trying to inherit attributes from a super class but they are not being initialized correctly:
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
super(Thing, self).__init__()
print self.attribute1
This throws an error since attribute1 is not an attribute of OtherThing, even though Thing.attribute1 exists. I thought this was the correct way to inherit and extend a super class. Am I doing something wrong? I don't want to create an instance of Thing and use its attributes, I need it to inherit this for simplicity.
You have to give, as argument, the class name (where it is being called) to super():
super(OtherThing, self).__init__()
According to Python docs:
... super can be used to refer to parent classes without naming them
explicitly, thus making the code more maintainable.
so you are not supposed to give the parent class.
See this example from Python docs too:
class C(B):
def method(self, arg):
super(C, self).method(arg)
Python3 makes this easy:
#!/usr/local/cpython-3.3/bin/python
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
#super(Thing, self).__init__()
super().__init__()
print(self.attribute1)
def main():
otherthing = OtherThing()
main()

initialize base class with variable not coming from derived class

I'm trying to provide framework which allows people to write their own plugins. These plugins are basically derived classes. My base class needs some variables to initialize, how can I initialize my base class without having to let my derived class feed the variable in the base class initialization?
#!/bin/python
class BaseClass():
def __init__(self,config):
self.config=config
def showConfig(self):
print "I am using %s" % self.config
class UserPlugin(BaseClass):
def __init__(self,config):
BaseClass.__init__(self,config)
def doSomething(self):
print "Something"
fubar = UserPlugin('/tmp/config.cfg')
fubar.showConfig()
My goal is to avoid the need to define the config parameter in the UserPlugin class, since this is something I don't want the user who writes a plugin to be bothered with.
You can use argument lists to pass any remaining arguments to the base class:
class UserPlugin(BaseClass):
def __init__(self, *args, **kwargs):
BaseClass.__init__(self, *args, **kwargs)
Based on your Pastebin code, how about this? This avoids using a separate global, instead using a class attribute, which is accessible as a member to all derived classes and their instances.
#!/bin/python
class BaseClass():
config = '/tmp/config.cfg'
def __init__(self):
pass
def showConfig(self):
print "I am using %s" % self.config
class UserPlugin(BaseClass):
def __init__(self):
BaseClass.__init__(self)
def doSomething(self):
print "Something"
fubar = UserPlugin()
fubar.showConfig()
This was the other way to do it that I mentioned before. Keep in mind that if you want to change the value of BaseClass.config itself, you should access it directly (i.e. BaseClass.config = '/foo/path'; otherwise, you wind up creating a custom UPinstance.config value, leaving BaseClass.config unchanged.

Categories