This recursive function (search_Bases
) would hopefully iterate through each base class and __init__
it. How do I refer to each class's self
, without actually using self
? I've tried a couple things but I can't figure it out. When I change the Child()
class up to do something similar, it works. So I have no clue what to do next.
def search_Bases(child=0):
if child.__bases__:
for parent in child.__bases__:
parent.__init__(self) # <-----I can't figure out how to initiate the class
# without referring to 'self'....
search_Bases(parent)
class Female_Grandparent:
def __init__(self):
self.grandma_name = 'Grandma'
class Male_Grandparent:
def __init__(self):
self.grandpa_name = 'Grandpa'
class Female_Parent(Female_Grandparent, Male_Grandparent):
def __init__(self):
Female_Grandparent.__init__(self)
Male_Grandparent.__init__(self)
self.female_parent_name = 'Mother'
class Male_Parent(Female_Grandparent, Male_Grandparent):
def __init__(self):
Female_Grandparent.__init__(self)
Male_Grandparent.__init__(self)
self.male_parent_name = 'Father'
class Child(Female_Parent, Male_Parent):
def __init__(self):
Female_Parent.__init__(self)
Male_Parent.__init__(self)
#search_Bases(Child)
child = Child()
print child.grandma_name
I don't think you properly understand class inheritance. In Python,
class Female_Parent(Female_Grandparent, Male_Grandparent):
def __init__(self):
means that Female_Parent
IS-A Male_Grandparent
, which seems unlikely. What you meant to say was
class Female_Parent(object):
def __init__(self, female_grandparent, male_grandparent):
This also has problems, in that the role changes depending on who is asking - by definition, a Male_Grandparent
(of his grandchildren) is also a Male_Parent
(of his children) who is also a Child
(of his parents).
You can boil all your classes down to
class Person(object):
def __init__(self, mother, father):
and derive further relationships from there. This gives a much simpler structure, without the point-of-view contradictions, but still results in problems evaluating further relationships because a given person's links only go "up" - a given person knows who their parents were, but can't identify their children.
You could keep a list of all your Persons and search the list each time (like a mother going around the kindergarten saying, "Are you my child? You? Are YOU my child?") but this seems very inefficient.
Instead, you can make each relationship two-way - each parent has a list of all their children and each child has a list of all their parents. It makes adding and removing people a little harder, but is well worth it.
The following is longer than I like but as short as I could make it; it should suit your needs much better!
class Person(object):
def __init__(self, name, sex, parents=None, children=None):
"""
Create a Person
"""
self.name = name
self.sex = sex # 'M' or 'F'
self.parents = set()
if parents is not None:
for p in parents:
self.add_parent(p)
self.children = set()
if children is not None:
for c in children:
self.add_child(c)
def add_parent(self, p):
self.parents.add(p)
p.children.add(self)
def add_child(self, c):
self.children.add(c)
c.parents.add(self)
def __str__(self):
return self.name
def __repr__(self):
return "Person('{}', '{}')".format(self.name, self.sex)
#
# Immediate relationships
#
# Each fn returns a set of people who fulfill the stated relationship
#
def _parent(self):
return self.parents
def _sibling(self):
return set().union(*(p.children for p in self.parents)) - set([self])
def _child(self):
return self.children
def _female(self):
if self.sex=='F':
return set([self])
else:
return set()
def _male(self):
if self.sex=='M':
return set([self])
else:
return set()
def relation(self, *rels):
"""
Find the set of all people who fulfill the stated relationship
Ex:
self.relation("parent", "siblings") # returns all aunts and uncles of self
"""
# start with the current person
ps = set([self])
for rel in rels:
# each argument is either a function or a string
if callable(rel):
# run the function against all people in the current set
# and collect the results to a new set
ps = set().union(*(rel(p) for p in ps))
else:
# recurse to evaluate the string
do = Person._relations[rel]
ps = set().union(*(p.relation(*do) for p in ps))
return ps
def print_relation(self, *rels):
print ', '.join(str(p) for p in self.relation(*rels))
#
# Extended relationships
#
# Supplies the necessary information for Person.relation() to do its job -
# Each key refers to a recursive function tree (nodes are string values, leaves are functions)
#
# (Unfortunately this table cannot be created until the Person class is finalized)
#
Person._relations = {
"parent": (Person._parent,),
"mother": (Person._parent, Person._female),
"father": (Person._parent, Person._male),
"sibling": (Person._sibling,),
"sister": (Person._sibling, Person._female),
"brother": (Person._sibling, Person._male),
"child": (Person._child,),
"daughter": (Person._child, Person._female),
"son": (Person._child, Person._male),
"grandparent": ("parent", "parent"),
"grandmother": ("parent", "mother"),
"grandfather": ("parent", "father"),
"aunt": ("parent", "sister"),
"uncle": ("parent", "brother"),
"cousin": ("parent", "sibling", "child"),
"niece": ("sibling", "daughter"),
"nephew": ("sibling", "son"),
"grandchild": ("child", "child"),
"grandson": ("child", "son"),
"granddaughter": ("child", "daughter")
}
and now, in action:
mm = Person('Grandma', 'F')
mf = Person('Grandpa', 'M')
m = Person('Mom', 'F', [mm, mf])
fm = Person('Nana', 'F')
ff = Person('Papi', 'M')
f = Person('Dad', 'M', [fm, ff])
me = Person('Me', 'M', [m, f])
s = Person('Sis', 'F', [m, f])
joe = Person('Brother-in-law', 'M')
s1 = Person('Andy', 'M', [s, joe])
s2 = Person('Betty', 'F', [s, joe])
s3 = Person('Carl', 'M', [s, joe])
me.print_relation("grandmother") # returns 'Nana, Grandma'
me.print_relation("nephew") # returns 'Andy, Carl'