How to inherit an updated attribute in Python - python-3.x

I'm trying to define two clases, A and B, with B being the child, as in the following code
class A:
def __init__(self, att_A=False):
self.att_A = att_A
def call_B(self):
b = B()
class B(A):
def __init__(self):
super().__init__()
print(f'{self.att_A=}')
a = A()
a.att_A = True
a.call_B()
B does properly inherit the methods and attributes at the time of definition but I want it to also access the values of self.att_A even when they were updated after being initiated.
Is it possible to do that or is there any workaround, like forwarding the attribute as a method parameter?
I have tried deffining att_A as a class attribute but still B cannot access the updated value

Related

Python pro way to make an abstract class allowing each child class to define its own attributes, Python3

I have to model several cases, each case is realised by a class. I want to make sure that each class must have 2 methods get_input() and run(). So in my opinion, I can write a CaseBase class where these 2 methods are decorated as #abstractmethod. Therefore, any child class has to implement these 2 methods. And this is exactly my goal.
However, due to the nature of my work, each case is for distinct subject, and it is not easy to define a fixed group of attributes. The attributes should be defined in the __init__ method of a class. That means I don't know what exactly attributes to write in the CaseBase class. All I know is that all children cases must have some common attributes, like self._common_1 and self._common_2.
Therefore, my idea is that I also decorate the __init__ method of CaseBase class by #abstractmethod. See my code below.
from abc import ABC, abstractmethod
from typing import Dict, List
class CaseBase(ABC):
#abstractmethod
def __init__(self):
self._common_1: Dict[str, float] = {}
self._common_2: List[float] = []
...
#abstractmethod
def get_input(self, input_data: dict):
...
#abstractmethod
def run(self):
...
class CaseA(CaseBase):
def __init__(self):
self._common_1: Dict[str, float] = {}
self._common_2: List[float] = []
self._a1: int = 0
self._a2: str = ''
def get_input(self, input_data: dict):
self._common_1 = input_data['common_1']
self._common_2 = input_data['common_2']
self._a1 = input_data['a1']
self._a2 = input_data['a2']
def run(self):
print(self._common_1)
print(self._common_2)
print(self._a1)
print(self._a2)
def main():
case_a = CaseA()
case_a.get_input(input_data={'common_1': {'c1': 1.1}, 'common_2': [1.1, 2.2], 'a1': 2, 'a2': 'good'})
case_a.run()
if __name__ == '__main__':
main()
My question: Is my way a good Python style?
I followed many Python tutorials about how to make Abstract class and child class. They all give examples where a fixed group of attributes are defined in the __init__ method of the base class. I also see some approach to use super().__init__ code in the child class to change the attributes defined in the base class or to add new attributes. But I am not sure if it is better (more pro) than my way.
Thanks.
You mostly used the abc module in python 3.10 correctly. but it doesn't make sense to decorate the constructor with #abstractmethod. It's unnecessary. Each class, derived or not, can and will have its own constructor. You can call super().__init__(args) within the child class to call the constructor of its immediate parent if you didn't want to duplicate its code but wanted to do further initialization in the child class constructor.

Python / Attributes between methods of a class

I'm new in Python and I'm trying to get my head around how are managed attributes between methods of a class.
In the following example, I'm trying to modify a list in the method "regex" and use it afterwards in another method "printsc".
The "regex" part works without issues, but the attribute "self.mylist" is not updated so when I call "printsc" the result is "None".
class MyClass():
def __init__(self):
self.mylist = None
def regex(self, items):
self.mylist = []
for item in items:
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", item):
self.mylist.append("IP:" + item)
else:
self.mylist.append("DNS:" + item)
return self.mylist
def printsc(self):
print(self.mylist)
items = ['192.168.0.1', 'hostname1', '10.0.1.15', 'server.local.fr']
MyClass().regex(items)
MyClass().printsc()
What am I missing ? What is the best way to achieve this goal ?
Thank you for your answers!
When you do MyClass(), it returns you an object.. And you are calling your methods on the object. Since you are doing it twice, each time a new object is created and regex and printsc are called on different objects.
what you should do is
myObj = MyClass()
myObj.regex(items)
myObj.printsc()
The problem is that when you do:
MyClass().regex(items)
MyClass().printsc()
You are creating 2 separate instances of MyClass, each of which will have a different .mylist attribute.
Either mylist is an instance attribute, and then this will work:
instance = MyClass()
instance.regex(items)
instance.printsc()
Or, if you want to share .mylist across instances, it should be
a class attribute:
class MyClass():
class_list = None
def __init__(self):
pass
def regex(self, items):
cls = self.__class__
if cls.class_list is None:
cls.class_list = []
for item in items:
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", item):
cls.class_list.append("IP:" + item)
else:
cls.class_list.append("DNS:" + item)
return cls.class_list
def printsc(self):
# Going throuhgh `.__class__.` is actually optional for
# reading an attribute - if it is not in the instance
# Python will fetch it from the class instead.
# i.e. , the line bellow would work with `self.class_list`
print(self.__class__.class_list)
This way, the list persists across different instances of the class, as you try to do in your example.
You should create an object of the class:
a = MyClass()
a.regex(items)
a.printsc()
>>> ['IP:192.168.0.1', 'DNS:hostname1', 'IP:10.0.1.15', 'DNS:server.local.fr']

python class not recognize class declared inside of her

this question must be a stupid one but important one and couldn't find any discussion about this in stackoverflow.
I'm trying to declare a class (lets say class 'B') inside another class (lets say 'A'), and use that class('B') in a method of class 'A', but for some reason in python you cannot declare an object member of class type that is declared in the same class.
why is that the case? in C you can access to the inner class from a method of the outside class without any problem...
(my intention that is only class A will ever need a member of type class B and i want only A to be able to find out that such a class like B...)
what is the proper way to do so in python?
class A:
def __init__(self):
self.B_object = B() # error 'unresolved refernace B'
class B:
def __init(self):
pass
class A:
def __init__(self):
self.B_object = A.B()
class B:
def __init(self):
pass
Try this
if you want to make B class private you can try this
class A:
def __init__(self):
self.__B_object = A.__B()
class __B:
def __init__(self):
pass

Find owner class of a method in Python

I'm writing decorators, and part of what I need to do is discern whether a function is a function or a method. Is there a way I can find what class a given method is a part of?
e.g. If I was to run this code, what could I write in getOwner to make exampleFunc print something like <class '__main__'.Example>?
class Example:
def method(self):
print("I'm a method")
def exampleFunc(func):
owner = getOwner(func)
print(owner)
test = Example()
exampleFunc(test.method)
If all you need to do is figure out of the thing behaving like a function is a method or a function, that is one purpose of the types module.
import types
def is_method(f):
return type(f) == types.MethodType
In the event that the function-like object is a method, you can find its parent class as follows.
Update Patched for Python3 compatibility.
def method_parent(f):
return f.__self__
If you have a reference to the classes defined in your scope, you'd need to check for each one:
def exampleFunc(f):
class_list = [...]
return any(f in vars(c).values() for c in class_List)
This will return True if function f is an instance method. However, if you wish to return the actual class name:
def exampleFunc(f):
class_list = [...]
for c in class_list:
if f in vars(c).values():
return c.__name__
return 'global function' if 'lambda' not in f.__name__ else 'lambda'
Note that this does not work for __dunder__ methods, and methods that your class inherits. For example,
class A:
def f1(self): pass
class B(A):
def f2(self): pass
print(vars(B))
mappingproxy({'__doc__': None,
'__module__': '__main__',
'f2': <function __main__.B.f2>})
Note that f1 is not a part of B's mappingproxy.

Reference Parent attributes from child - python3

I have what I thought would be a pretty straightforward task, but it has turned into me questioning everything I know about Classes (which to be fair wasn't much to begin with).
I have a parent class and I want to use the attributes of that instance in calculations to be performed in the child class, which is to be created from the init of the parent class. However, I don't seem to be able to reference them from the child class.
I have found some suggestions to init the parent class from the child class, however, that just creates an endless loop in my case.
class User(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.child.append(Child(c=4))
class Child(User)
def __init__(self, c):
self.c = c + User.b
print self.c
From the code and the question, I'm guessing Child really just needs to access some attributes of User, in this example self.b
Inheritance is not the way to go. Inheritance is when you want to reuse a lot of attributes and methods, and re-implement some of them. Like two class "car" and "truck" would both inherits from a class "vehicles"
What you describe with the "Parent-Child" is more like ownership. The class User owns some Child (as attributes), and you want the Child to access data from their owner. What you need to do is to pass a reference of the owner (parent) to the child.
class User(object):
def __init__(self, b):
self.b = b
self.child.append(Child(c=4,parent=self))
class Child(object)
def __init__(self, c, parent):
self.parent=parent
self.c = c + self.parent.b
print(self.c)
Of course in this really simple example, the most obvious way to program it would be to pass b in the child constructor, like this:
class User(object):
def __init__(self, b):
self.b = b
self.child.append(Child(4,b))
class Child(object)
def __init__(self, c, b):
self.c = c + .b
print(self.c)
But for a more complex task, passing a reference to the parent can be better or necessary.

Resources