0
initialTreeCom=['ADD_CHILD None King_Shan Male','ADD_CHILD None Queen_Anga Female',
                 'AM King_Shan Queen_Anga','ADD_CHILD Queen_Anga Chit Male']

famTree=familyTree.FamiltyTree(initialTreeCom)
result=famTree.excommand('GET_RELATIONSHIP Chit Father')
print(result)

Q1. when i create an object of class FamilyTree which inherits from class Relationships . how is a function called excommand of class FamilyTree able to call a function of parent class as

getattr(self, argument[2].replace('-','_'))(argument[1])

but throws an error when i get the function reference by gettr function by using super (since i want to access function of parent class) instead of self?

Q2. How is the called function Father of super class Relationships able to access variable familyMembers of subclass FamilyTree using self.familyMembers ?

    class Person():
            def __init__(self,mother,name,gender):
                self.name=name
            self.gender=gender
            self.mother=mother
            self.marriedTo=None

        def add_partner(self,marriedTo):
            """
            Assigns passed marriedTo value to marriedTo attribute to calling objects
            """
            if marriedTo != self.marriedTo:
                self.marriedTo=marriedTo

    class FamiltyTree(Relationships):
        familyMembers=OrderedDict()
        def __init__(self,initialTree):        
            for i,line in enumerate(initialTree):
                # print('executing command',i,' : ',line)
                self.excommand(line)

        def excommand(self,command):
            """
            Executes the passed command
            Commands : ADD_CHILD, GET_RELATIONSHIP
            """
            argument=command.split()
            if argument[0]=='ADD_CHILD':
                # print('adding child')
                p=Person(argument[1], argument[2], argument[3])
                return self.add_Person(p)
            if argument[0]=='AM':
                # print('adding married to')
                return self.add_MarriedTo(argument[1], argument[2])
            if argument[0]=='GET_RELATIONSHIP':
                if argument[1] not in self.familyMembers:
                    return 'PERSON_NOT_FOUND'
                # print('getting relationship',argument[2], 'for : ',argument[1])
                **res= getattr(self,argument[2].replace('-','_'))(argument[1])**
                if res:
                    return ' '.join(res)
                return None

        def add_Person(self,person):
            """
            Adds passed Person to Family members, of calling object of FamiltyTree
            """
            if person.mother!='None' and  person.mother not in self.familyMembers:
                return 'PERSON_NOT_FOUND'
            if isinstance(person,Person) and person.name not in self.familyMembers and (person.mother=='None' or self.familyMembers[person.mother].gender=='Female'):
                self.familyMembers[person.name]=person
                return 'CHILD_ADDITION_SUCCEEDED'
            else:
                return 'CHILD_ADDITION_FAILED'

        def add_MarriedTo(self,person1,person2):
            """
            sets marriedTo Relationship among both passed person objects to each other.
            """
            if person1 in self.familyMembers and person2 in self.familyMembers:
                for key , value in self.familyMembers.items():
                    if key==person1:
                        value.add_partner(person2)
                    if key==person2:
                        value.add_partner(person1)
                return True
            else:
                return False

    class Relationships():

        def Father(self,name):
            """
            Finds Father of passed person name
            """
            if name in self.familyMembers:
                for key , value in self.familyMembers.items():
                    if self.familyMembers[self.familyMembers[name].mother].marriedTo==key:
                        return key
            return None
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

1 Answers1

-1

A1. getattr() is searching for a member whose name corresponds to the string you pass it. In your case, the name is Father. This is a convenient way of mapping strings the user inputs (argument[2] in your case) so that you can see if an implementation of that relationship exists in the Relationships class.

This is clever. Now you can just add implementations for other relationships to the Relationship class without having to modify the implementation of GET_RELATIONSHIP.

Alternatively, you could have implemented Father as:

if argument[2] == 'Father':
   res = self.Father(argument[1])

But then you'd have do that for every type of relationship you want to implement (eg, Brother, Cousin).

This Relationships class makes it easy for you to just implement individual relationships by walking the family tree. The Father() implementation is a good example of how to do that.

A2. Because when Python encounters self.x, it first searches the current class for a data attribute x, and if it finds none, it then proceeds to search for a class attribute x, and uses that for subsequent operations on self.x. In your case, familyMembers is class attribute, and it happens to be located in the superclass Relationships. super only looks at data members.

There is an excellent discussion of class and instance attributes here

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Rusty Widebottom
  • 985
  • 2
  • 5
  • 14
  • yes i added getattr() for the same reason . my question is why am i able to access a function of parent class using 'self' , whereas my first instinct was to use 'super' , but to my surprise it threw error. in Q2 i am basically confused as to how the superclass functions are able to access a child class's class member using 'self' . – Ankit Veer Singh May 13 '20 at 16:50