Abstarct

import abc
class IMenu(abc.ABC):
def __init__(self, s):
self.text = s
self.components = list()
@abc.abstractmethod
def addMenu(self):
pass
class Menu(IMenu):
def addMenu(self, text):
self.components.append(Menu(text))

def traverse(self, prefix):
self._traverse(prefix)

def _traverse(self, prefix):
print(f"{prefix} {self.text}")
for menu in self.components:
menu._traverse(prefix + prefix)

def get(self, text):
for menu in self.components:
if menu.text == text:
return menu

mainMenu = Menu("file")
mainMenu.addMenu("open")
mainMenu.addMenu("save")
mainMenu.addMenu("exit")

mainMenu.get("open").addMenu("open local")
mainMenu.get("open").addMenu("open box")
mainMenu.get("open").addMenu("open istore")

mainMenu.get("save").addMenu("save local")
mainMenu.get("save").addMenu("save box")
mainMenu.get("save").addMenu("save istore")

New

"""
Whenever a class is instantiated __new__ and __init__ methods are called. __new__ method will be called when an object is created and __init__ method will be called to initialize the object.
In the base class object, the __new__ method is defined as a static method which requires to pass a parameter cls. cls represents the class that is needed to be instantiated, and the compiler automatically provides this parameter at the time of instantiation.
New is the first step of instance and is responsible for returning a new instance of your class.
Init does not return anything and is responsible for initializing the instance.
"""
class A(object):
def __new__(cls):
print("Creating instance")
return super(A, cls).__new__(cls)

def __init__(self):
print("Init is called")

def foo(self):
print("foo")
a = A()
a.foo()

New Inheritance

class A(object):
def __init__(self):
print("-> A")
#super(A, self).__init__()
print("<- A")
class B(object):
def __init__(self):
print("-> B")
#super(B, self).__init__()
print("<- B")
class C(A, B):
def __init__(self):
print("-> C")
# Use super here, instead of explicit calls to __init__
# super(C, self).__init__() # CALL all __init__ AFTER C, which is B
# super(A, self).__init__() # CALL all __init__ AFTER A, which is B
# super(B, self).__init__() # CALL all __init__ AFTER B, which is Object
#A.__init__(self) # CAll from A
#B.__init__(self) # CAll from B

class Base1:
def __init__(self):
print("Base1")
class Base21(Base1):
def __init__(self):
print("Base21")
super().__init__() # Error due to MRO. Base21 calls Base22 __init__ But it needs string argument.
class Base22(Base1):
def __init__(self, string):
print("Base22")
super().__init__() #Base1.__init__(self)
print(string)

# Problematic inheritance
# class Base3(Base21, Base22):
# def __init__(self):
# Base21.__init__(self)
# Base22.__init__(self, "initialize base22")
# print("Base3")
# correct inheritance
class Base3(Base22, Base21):
def __init__(self):
Base21.__init__(self)
Base22.__init__(self, "initialize base22")
print("Base3")
b3 = Base3()

MRO

class A:
def func(self):
return 'A.func'
class B(A):
def func(self):
return 'B.func'
class C(A):
def func(self):
return 'C.func'
class D( B, C):
pass
class E( C, B):
pass

print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
print(D().func()) # B.func

print(E.mro()) # [<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
print(E().func()) # C.func
class Tokenizer:
"""Tokenize text"""
def __init__(self, text):
print('Start Tokenizer.__init__()')
self.tokens = text.split()
print('End Tokenizer.__init__()')

class WordCounter(Tokenizer):
"""Count words in text"""
def __init__(self, text):
print('Start WordCounter.__init__()')
super().__init__(text)
self.word_count = len(self.tokens)
print('End WordCounter.__init__()')

class Vocabulary(Tokenizer):
"""Find unique words in text"""
def __init__(self, text):
print('Start init Vocabulary.__init__()')
super().__init__(text)
self.vocab = set(self.tokens)
print('End init Vocabulary.__init__()')

class TextDescriber(WordCounter, Vocabulary):
"""Describe text with multiple metrics"""
def __init__(self, text):
print('Start init TextDescriber.__init__()')
super().__init__(text)
print('End init TextDescriber.__init__()')

td = TextDescriber('row row row your boat')
print('--------')
print(td.tokens)
print(td.vocab)
print(td.word_count)