Access Composite class fields from Component class

Viewed 262

I have two classes 'Employee' (composite class) and 'Salary' (component class).

I want to get value of a variable named 'self.abc' (defined in Employee class) in 'Salary' class. How can I get that?

Currently I'm getting an error AttributeError: 'Salary' object has no attribute 'abc'. Please help.

I don't wanna use inheritance approach here.

class Employee:
    def __init__(self, pay, bonus):
        self.abc = 100
        self.pay = pay
        self.bonus = bonus
        self.obj_salary = Salary(self.pay)
        self.annual_salary()
 
    def annual_salary(self):
        print("Total: " + str(self.obj_salary.get_total() + self.bonus))


class Salary:
    def __init__(self, pay):
        self.pay = pay
 
    def get_total(self):
        print(self.abc) # want to get 'abc' value here from 'Employee' class
        return (self.pay*12)
 
 
obj_emp = Employee(600, 500)
2 Answers

One solution would simply be to pass the Employee object as an argument to the Salary constructor, like so:

class Employee:
    def __init__(self, pay, bonus):
        self.abc = 100
        self.pay = pay
        self.bonus = bonus
        self.obj_salary = Salary(self)
        self.annual_salary()
 
    def annual_salary(self):
        print("Total: " + str(self.obj_salary.get_total() + self.bonus))


class Salary:
    def __init__(self, parent):
        self.pay = parent.pay
        self.parent = parent
 
    def get_total(self):
        print(self.parent.abc)
        return (self.pay*12)
 
 
obj_emp = Employee(600, 500)

Note that in the above code, obj_emp.obj_salary.pay will not be updated if obj_emp.pay is, meaning in the following code:

obj_emp = Employee(600, 500)
obj_emp.pay = 700
print(obj_emp.obj_salary.pay)

The last print statement will print 600, not 700.

If you ever do need to reference pay dynamically within Salary, you can always use self.parent.pay rather than self.pay; this will refer to the connected Employee object's pay value.

You'd have to explicitly tell Salary thay information when you initialize it, or after. You could pass the abc value to the initializer along with pay:

class Salary:
    def __init__(self, pay, abc):
        self.employee_abc = abc

and then in Employee.__init__:

self.obj_salary = Salary(self.pay, self.abc)

or give Salary the instance of Employee that it's a member of and access abc through that:

self.obj_salary = Salary(self.pay, self)

The benefit of the first way is you're only telling Salary enough information for it to be able to do its job, which is good. You don't want Salary depending heavily on the design of Employee.

The benefit of the second way is if you change self.abc in the Employee object, it will automatically be reflected in the Salary as well (although, this could also be seen as a down-side).

Related