Reference Parent attributes from child - python3 - python-3.x

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.

Related

How to inherit an updated attribute in Python

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

How __init__ works for inheritance

I cant have 2 init methods in one class because of function overloading. However, why is it possible that when initializing a subclass, im able to define a new __init__ method, and use the super().__init__ method or the parentclass init method within the subclass __init__ method. i'm just a little confused by the concept of 2 __init__ methods functioning at the same time
class Employee:
emps = 0
def __init__(self,name,age,pay):
self.name = name
self.age = age
self.pay = pay
class Developer(Employee):
def __init__(self,name,age,pay,level):
Employee.__init__(self,name,age,pay)
self.level = level
I cant have 2 init methods in one class because of function overloading.
Partially true. You can't have 2 __init__ methods in the same class because the language lacks function overloading. (Libraries can partially restore a limited form of function overloading; see functools.singledispatchmethod for an example.)
i'm just a little confused by the concept of 2 init methods functioning at the same time
But you aren't trying to overload __init__. You are overriding __init__, providing a different definition for Developer than the definition it inherits from Employer. (In fact, Employer is overriding __init__ as well, using its own definition in place of the one it inherits from object.) Each class has only one definition.
In your definition of Developer.__init__, you are simply making an explicit call to the inherited method to do the initialization common to all instances of Employee, before doing the Developer-specific initialization on the same object.
Using super, you are using a form of dynamic lookup to let the method resolution order for instance of Developer decide what the "next" version of __init__ available to Developer to call. For single inheritance, the benefit is little more than avoiding the need to hard-code a reference to Employee. But for multiple inheritance, super is crucial to ensuring that all inherited methods (both the ones you know about and the ones you may not) get called, and more importantly, are called in the right order.
A full discussion of how to properly use super is beyond the scope of this question, I think, but I'll show your two classes rewritten to make the best use of super, and refer you to Python's super() considered super! for more information.
# Main rules:
# 1. *All* classes use super().__init__, even if you are only inheriting
# from object, because you don't know who will use you as a base class.
# 2. __init__ should use keyword arguments, and be prepared to accept any
# keyword arguments.
# 3. All keyword arguments that don't get assigned to your own parameters
# are passed on to an inherited __init__() to process.
class Employee:
emps = 0
def __init__(self, *, name, age, pay, **kwargs):
super().__init__(**kwargs)
self.name = name
self.age = age
self.pay = pay
class Developer(Employee):
def __init__(self, *, level, **kwargs):
super().__init__(**kwargs)
self.level = level
d1 = Developer(name="Alice", age=30, pay=85000, level=1)
To whet your appetite for the linked article, consider
class A:
def __init__(self, *, x, **kwargs):
super().__init__(**kwargs)
self.x = x
class B:
def __init__(self, *, y, **kwargs):
super().__init__(**kwargs)
self.y = y
class C1(A, B):
pass
class C2(B, A):
pass
c1 = C1(x=1, y=2)
c2 = C2(x=4, y=3)
assert c1.x == 1 and c1.y == 2
assert c2.x == 4 and c2.y == 3
The assertions all pass, and both A.__init__ and B.__init__ are called as intended when c1 and c2 are created.
The super() function is used to give access to methods and properties of a parent or sibling class
check out: https://www.geeksforgeeks.org/python-super/

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 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

How to use tkinter entry .get() fuction in another class

I'm struggling to get a variable entry getter from another class, i know i have to pass the instance of the class im getting the variable from, but how would i use the actual variable in the class i would like to use it in?
Here is the class:
class NewEmployee:
def __init__(self, master):
self.master = master
self.master.title("Jans Corp")
self.master.configure(background="lightgrey")
self.master.geometry("300x500")
self.FirstNameEntry = tk.Entry(self.master)
self.SurnameEntry = tk.Entry(self.master)
self.AgeEntry = tk.Entry(self.master)
self.PostcodeEntry = tk.Entry(self.master)
Here is where i'd like to use self.FirstNameEntry.get()
class Database(NewEmployee):
def __init__(self, master):
conn = sqlite3.connect(':memory:')
c = conn.cursor()
def addEmployees(self):
with conn:
c.execute("INSERT INTO Employees VALUES (:first, :last, :age)",
{'first':emp.first, 'last':emp.last, 'age':emp.age, }) <-----
Here you can see i have added the instance of the class im want to get the info from but do not know how to call "FirstNameEntry.get()" in the database class.
Would i have to use NewEmployee.FirstNameEntry() or would it be something else?
Here you can see i have added the instance of the class im want to get the info from...
That is not how classes work. Inheritance is a "is a" relationship. Your code is saying that your Database class "is a" NewEmployee, which is clearly not true. Databases are not employees.
The way to do this is to pass an instance of Employee to your addEmployee method. Roughly speaking, it looks like this:
emp = NewEmployee()
db = Database()
db.addEmployee(emp)
That means that you need to modify addEmployee to accept the employee to be added, and to call the get method of the widgets:
class Database():
...
def addEmployee(self, emp):
with conn:
c.execute(..., {'first':emp.FirstNameEntry.get(),...})
Note that it's rather unusual to have something like an Employee class that has widgets in it. Usually it just has data, and you would have a separate class to represent the GUI (ie: you have one GUI but many employees)
For example, your GUI class would be:
class EmployeeForm():
def __init__(self):
...
self.firstNameEntry = tk.Entry(...)
...
You would create one instance of this at the start of your program:
class TheApplication():
def __init__(self):
...
self.employeeForm = EmployeeForm()
...
You might then have an Employee class that looks something like this:
class Employee():
def __init__(self, first, last, etc):
self.first = first
self.last = last
self.etc = etc
Then, you might add a getEmployee method in your GUI class like this:
class EmployeeForm():
...
def getEmployee(self):
first = self.firstEntry.get()
last = self.lastEntry.get()
etc = self.etcEntry.get()
return Employee(first, last, etc)
Then, somewhere in your code -- maybe the "save" button on the form or application -- you would do something like this:
employee = self.employeeForm.getEmployee()
db.addEmployee(employee)
That's not another class ... that's a subclass. You would call it the same way you defined it: with self. Also, remember that with all subclasses, you have to call the parent __init__ from the subclass.
class Database(NewEmployee):
def __init__(self, master):
super().__init__(master) #call parent __init__
conn = sqlite3.connect(':memory:')
c = conn.cursor()
def addEmployees(self):
with conn:
c.execute("INSERT INTO Employees VALUES (:first, :last, :age)",
{'first':self.FirstNameEntry.get(), 'last':self.SurnameEntry.get(), 'age':self.AgeEntry.get(), })

Resources