Python Class Multiple Inheritance Only Inherit Variables From One Parent? - python-3.x

I'm confused about the way Python class inherit from multiple parent classes.
If the parent classes all inherit from the same grand-parent class, everything is wonderful.
# grand-parent class
class Z():
def __init__(self):
pass
# parent class A
class A(Z):
def __init__(self):
super().__init__()
self.x = 1
# parent class B
class B(Z):
def __init__(self):
super().__init__()
self.y = 2
# parent class C
class C(Z):
def __init__(self):
super().__init__()
self.z = 3
# target class D
class D(A, B, C):
def __init__(self):
super().__init__()
d = D()
print(vars(d))
#{'x': 1, 'y': 2, 'z': 3}
Without the same grand-parent class, only variables from the first parent class is inherited.
# parent class A
class A():
def __init__(self):
self.x = 1
# parent class B
class B():
def __init__(self):
self.y = 2
# parent class C
class C():
def __init__(self):
self.z = 3
# target class D
class D(A, B, C):
def __init__(self):
super().__init__()
d = D()
print(vars(d))
#{'x': 1}

Python's method resolution order works from Left to Right. It will only call the init method of the first class(A in your case).
This will give you the desired result-
class A():
def __init__(self):
super().__init__()
self.x = 1
# parent class B
class B():
def __init__(self):
super().__init__()
self.y = 2
# parent class C
class C():
def __init__(self):
self.z = 3
# target class D
class D(A, B, C):
def __init__(self):
super().__init__()
d = D()
print(vars(d))

Related

position of super().__init__() gives different output

I was trying to understand this example working.
class P:
def __init__(self):
self.__x=100
self.y=200
def print(self):
print(self.__x, self.y)
class C(P):
def __init__(self):
super().__init__() <-------------------
self.__x=300
self.y=400
d = C()
d.print()
output: 100 400
class P:
def __init__(self):
self.__x=100
self.y=200
def print(self):
print(self.__x, self.y)
class C(P):
def __init__(self):
self.__x=300
self.y=400
super().__init__() <--------------------
d = C()
d.print()
output: 100 200
Can someone explain the execution flow of the above codes leading to separate outputs?

How to Access Outer class variables in Inner Class (Python)?

How to access the variables of the outer class in the Inner Class?
class Student:
def __init__(self,Name,rollNumber):
self.Name=Name
self.rollNumber=rollNumber
self.lap=self.Laptop()
def Show(self):
print(self.Name)
print(self.lap.show())
class Laptop:
def __init__(self):
self.brand = "Mac"
self.cpu = "i9"
self.ram = 16
def show(self):
return self.brand
#staticmethod
def Show():
return s1.Name
s1=Student("Teja",2)
print(s1.Name,s1.rollNumber)
s1.Show()
print(s1.lap.brand)
system=s1.lap
print(system.brand)
print(system.cpu)
print(system.show())
print(system.Show())

How can I access methods of a class that is passed as argument to another class in python

I want to create a class(say, LockedAttributes) to access(READ/WRITE) some attributes safely by multiple threads.I want to pass those attributes that I want to share as a list to the LockedAttributes class. Some of the list elements are itself class objects with it's own setter and getter.
How can i access those setter/getter from a LockedAttribute class obj?
My use of getattr() setattr() might be wrong.
sample code:
class Coord:
def __init__(self, x=0.0, y=0.0, z=0.0):
self.x = x
self.y = y
self.z = z
def set_coordinator(self, x, y, z):
self.x = x
self.y = y
self.z = z
def get_coordinator(self):
return self.x, self.y, self.z
class LockedAttributes(object):
def __init__(self, obj):
self.__obj = obj
self.__lock = RLock()
def getmyPosition(self):
with self.__lock:
return self.__obj[0]
def getmySpeed(self):
with self.__lock:
return self.__obj[1]
def getcolPosition(self):
with self.__lock:
return self.__obj[2]
def getDistfromCol(self):
with self.__lock:
getattr(self, self.__obj[3])
def setDistfromCol(self, value):
with self.__lock:
setattr(self, self.__obj[3], value)
def getcolactivationFlag(self):
with self.__lock:
getattr(self, self.__obj[4])
def setcolactivationFlag(self, value):
with self.__lock:
setattr(self, self.__obj[3], value)
class OBU():
def __init__(self):
pos = Coord()
speed = Coord()
colpos = Coord()
distance_from_accident = 0.0
Flag = False
self.shared_attributes = LockedAttributes([ pos, speed, colpos, distance_from_accident, Flag])
mypos= self.shared_attributes.getmyPosition()
mypos.get_coordinator() # Not workinh
The __init__ method of the LockedAttributes class should take an argument so that you can actually pass a list object to it.
Change:
class LockedAttributes(object):
def __init__(self):
self.__obj = object
self.__lock = RLock()
To:
class LockedAttributes(object):
def __init__(self, obj):
self.__obj = obj
self.__lock = RLock()

change method resolution order

is it possible to change the method resolution order?
class A(object):
def __init__(self, a):
self.a=a
def method(self):
print('A method')
class B(object):
def __init__(self, b1, b2):
self.b1=b1
self.b2=b2
def method(self):
print('B method')
class C(A, B):
def __init__(self, name, **kwargs):
if name=='A':
A.__init__(self, a=kwargs['a'])
elif name=='B':
B.__init__(self, b1=kwargs['b1'], b2=kwargs['b2'])
I want change the MRO if the input name is 'B', so that when i call:
>>>c=C(name='B', b1=2, b2=3)
>>>c.method()
it returns 'B method'.
Thanks
Just change the definition of the C class to :
class C(B, A):
...
ie : change the order of the inherited classes.

Override abstract setter of property in Python 3

What is the simplest / most pythonic way to override only the setter of an abstract property in Python 3? Variant 3 seems to mean the least effort for the derived class implementor. Is it correct? Does it have disadvantages?
import abc
class A1(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
#property
def x(self):
return self._x
#x.setter
#abc.abstractmethod
def x(self, value):
self._x = value
class B1(A1):
#property
def x(self):
return super().x
#x.setter
def x(self, value):
print("B1 setter")
super(B1, self.__class__).x.fset(self, value)
b1 = B1(x=1)
b1.x = 3
print(b1.x)
class A2(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
#abc.abstractmethod
def _get_x(self):
return self._x
#abc.abstractmethod
def _set_x(self, value):
self._x = value
x = property(_get_x, _set_x)
class B2(A2):
def _get_x(self):
return super()._get_x()
def _set_x(self, value):
print("B2 setter")
super()._set_x(value)
x = property(_get_x, _set_x)
b2 = B2(x=1)
b2.x = 3
print(b2.x)
class A3(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
def _get_x(self):
return self._x
#abc.abstractmethod
def _set_x(self, value):
self._x = value
x = property(
lambda self: self._get_x(),
lambda self, value: self._set_x(value))
class B3(A3):
def _set_x(self, value):
print("B3 setter")
super()._set_x(value)
b3 = B3(x=1)
b3.x = 3
print(b3.x)
So, yes, you listed a lot of ways in there - and although the one that requires more code is your variant 3, the most straighforard, least surprising way to do it is your variant 1 -
It just works, and is perfectly readable, no surprises - and there seems to be no simpler way than calling fget explicitly there.

Resources