Python Multiple Inheritance - values not accessible - python-3.x

I have a few classes set up that hold values for an application. I'd like to import them into the same class, however, the values in the last class are being ignored. Here is a simple example.
class A:
def __init__(self):
self.testA = 'A'
class B:
def __init__(self):
self.testB = 'B'
class C(A, B):
def __init__(self):
super().__init__()
print(self.testA)
print(self.testB)
test = C()
The above will work only if I do not include the print(self.testB) the variable in class 'B'. I'd like to access the data from Class B as well. How? Thank you.

Related

Instantiate parent class only once when calling from two child classes

I would like to know if there's a way that we can instantiate a class only once when called from one of the child class and somehow cache it and use it for second child class without instantiating the parent class.
class A:
def __init__(self):
#some huge data stored in self parameters.
class B:
def __init__(self):
A.__init__(self)
class C:
def __init__(self):
A.__init(self)
So both classes B and C uses class A as a parent class and class A has huge data initialised which can be used by both classes B and C. So what I'm trying to achieve here is when I instantiate class B for example, it instantiates class A and loads all the data into memory and to cache the instance so when I immediately instantiate class C it looks for the existing instance of the class without instantiating it again.
How about instantiating A in B and providing a method to transfer the data from B to outside? See below:
class A:
def __init__(self):
self.huge_data = [.....]
def data(self):
return self.huge_data
class B:
def __init__(self):
self.a = A()
def pass_data(self)
return a.data()
class C:
def __init__(self):
A.__init(self)
Once you instantiate B, you will be able to use the method to access the data.

How to write a Python class with different methods in different cases?

Suppose we have two classes A and B
class A:
def __init__(self):
pass
def print_abc(self):
print('abc')
class B:
def __init__(self):
pass
def print_def(self):
print('def')
We use class A in the case when we want to work with storageA, and class B when we want to work with storageB. Now, is there a way to write one class, named C, which uses method print_abc if storageA is in question and print_def if storageB is in question? In some sense hypothetical something like this:
class C:
def __init__(self, storage):
self.storage = storage
#storage=storageA
def print_abc(self):
print('abc')
#storage=storageB
def print_def(self):
print('def')
Is something like this possible and how?

Cross class calling through 'sibling' inheritance?

I'm wondering if what I have created is valid and 'nice' - or actually a mess
I have a class that has a method which calls a function in another class. However, it is only 'visible' by the fact these two classes are brought together in another child class. If somebody is just looking at this method they may wonder where this is actually located - it is not clear.
Am I doing something wrong here, or something common in Python?
class A():
def __init__(self):
pass
def register_urc(self, text):
print(text)
class B(A):
def __init__(self):
A.__init__(self)
class C():
def __init__(self):
self.register_urc("Hello World")
class Z(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
def test(self):
print("finished")
z = Z()
z.test()
What I get is:
Hello World
finished.
I assume this is working because I'm referencing Z's 'self' and passing that down to all other classes.

Class inheritance python 3.6 : Similar methods

I'm not the strongest pillar when it comes to class inheritance, so here goes my rather silly question. Following the code below, I would logically assume that after the 'super' call, the pointer arrives at self.example() which would in turn refer to the 'example' method in the same class and value 20 will be printed.
class A(object):
def __init__():
self.example()
def example(self):
print(20)
class B(A):
def __init__():
super().__init__()
def example(self):
print(10)
x = B()
Result : 10
This clearly isn't the case and 10 is printed instead. Could someone please shed some light on the mysterious world of class inheritance.
class A(object):
def __init__():
self.example()
def example(self):
print(20)
class B(A):
def __init__():
super().__init__()
x = B()
x.example()
Look for this, at example.
When you inherit B, from A, then method example is inheritated to B, you not must rewrite this to B. Of course still you can write this method for B, then you will override 'A' method, for objects of class B.
You also can use one class to Inheritance with many others:
class Base(object):
def __init__(self):
print("Base created")
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super(ChildB, self).__init__()
ChildA()
ChildB()
ChildB have another call which is equivalent to that used in example above.

dynamic class inheritance using super

I'm trying to dynamically create a class using type() and assign an __init__ constructor which calls super().__init__(...); however, when super() gets called I receive the following error:
TypeError: super(type, obj): obj must be an instance or subtype of type
Here is my code:
class Item():
def __init__(self, name, description, cost, **kwargs):
self.name = name
self.description = description
self.cost = cost
self.kwargs = kwargs
class ItemBase(Item):
def __init__(self, name, description, cost):
super().__init__(name, description, cost)
def __constructor__(self, n, d, c):
super().__init__(name=n, description=d, cost=c)
item = type('Item1', (ItemBase,), {'__init__':__constructor__})
item_instance = item('MyName', 'MyDescription', 'MyCost')
Why is super() inside the __constructor__ method not understanding the object parameter; and how do I fix it?
Solution 1: Using cls = type('ClassName', ...)
Note the solution of sadmicrowave creates an infinite loop if the dynamically-created class gets inherited as self.__class__ will correspond to the child class.
An alternative way which do not have this issue is to assigns __init__ after creating the class, such as the class can be linked explicitly through closure. Example:
# Base class
class A():
def __init__(self):
print('A')
# Dynamically created class
B = type('B', (A,), {})
def __init__(self):
print('B')
super(B, self).__init__()
B.__init__ = __init__
# Child class
class C(B):
def __init__(self):
print('C')
super().__init__()
C() # print C, B, A
Solution 2: Using MyClass.__name__ = 'ClassName'
An alternative way to dynamically create class is to define a class inside the function, then reassign the __name__ and __qualname__ attributes:
class A:
def __init__(self):
print(A.__name__)
def make_class(name, base):
class Child(base):
def __init__(self):
print(Child.__name__)
super().__init__()
Child.__name__ = name
Child.__qualname__ = name
return Child
B = make_class('B', A)
class C(B):
def __init__(self):
print(C.__name__)
super().__init__()
C() # Display C B A
Here is how I solved the issue. I reference the type() method to dynamically instantiate a class with variable references as such:
def __constructor__(self, n, d, c, h):
# initialize super of class type
super(self.__class__, self).__init__(name=n, description=d, cost=c, hp=h)
# create the object class dynamically, utilizing __constructor__ for __init__ method
item = type(item_name, (eval("{}.{}".format(name,row[1].value)),), {'__init__':__constructor__})
# add new object to the global _objects object to be used throughout the world
self._objects[ item_name ] = item(row[0].value, row[2].value, row[3].value, row[4].value)
There may be a better way to accomplish this, but I needed a fix and this is what I came up with... use it if you can.

Resources