1

I solve this problem:

Develop an application which operates with next types:

  1. Person (field Name, method ShowData())
  2. Student (field Education)
  3. Worker (field WorkPlace)

Classes Student and Worker are derived from class Person.

Class Academy in it's container collects Students and Workers and shows Name, Education or WorkPlace for all persons in method ShowAll().

We can add new persons to Academy by calling method AddPerson().

Which hierarchy of classes is the best for solving this problem?

Code should include inheritance and use collections.

This is my solution, but i don't know how to realize method AddPerson:

class Academy(object):
    theWholeList = []
    @staticmethod
    def showAll():
        for obj in Academy.theWholeList:
            if isinstance(obj,Student):
                print obj.name+' - '+obj.edu
            elif isinstance(obj,Worker):
                print obj.name+' - '+obj.wplace

class Person(Academy):
    def __init__(self,name):
        self.name = name
        super(Person, self).theWholeList.append(self)

    def showData(self):
        return vars(self)

class Student(Person):

    def __init__(self, name, edu):
        super(Student, self).__init__(name)
        self.edu = edu

class Worker(Person):

    def __init__(self, name, wplace):
        super(Worker, self).__init__(name)
        self.wplace = wplace

Maybe Academy must inherit Person and method AddPerson will be like that:

def add(self,name):
    super(Academy,self).__init__(name)
2
  • 2
    Looks like homework, but I'll say showAll should not be a staticmethod. Commented Sep 9, 2015 at 21:21
  • 2
    And this is fall again! Another batch of students struggling to get their homework done on SO ;-) Commented Sep 9, 2015 at 21:26

2 Answers 2

2

first thing:

class Academy(object):
    theWholeList = []
    @staticmethod
    def showAll():
        for obj in Academy.theWholeList:
            if isinstance(obj,Student):
                print obj.name+' - '+obj.edu
            elif isinstance(obj,Worker):
                print obj.name+' - '+obj.wplace

you do not need to have Academy's method showAll() be a static method, as on your design the Academy is legitimate to be a singleton, i.e. a class having a single instance.

Also theWholeList is a very bad name for a list. Because you know it is a list, as you're assigning it a list. The name shall describe its semantic, i.e. the kind of things it contains, what it is used for.

You should rewrite it as follows:

class Academy:
    def __init__(self):
        self.person_list = []

    def show_all(self):
        for item in self.person_list:
            item.show_data()

And you would instanciate it once:

academy = Academy()

Then the following:

class Person(Academy):
    def __init__(self,name):
        self.name = name
        super(Person, self).theWholeList.append(self)

is bad design: in object oriented programming you should think about encapsulating data. Here you're making the assumption that Person knows the internals of Academy. And what if you decide to change Academy's implementation so theWholeList is renamed? Or switched into a dict()? This should be transparent to the "user" of the class Academy. A better design should be:

class Academy:
    ... # cf earlier

    def add_person(self, person):
        self.person_list.append(person)

class Person(Academy):
    def __init__(self,name):
        self.name = name

    def show_data(self):
        print("My name is: {}".format(name))

So you can use it as follows:

person_a = Person("John Doe")
person_b = Person("Jim Smith")
academy.add_person(person_a)
academy.add_person(person_b)

And finally you're wondering:

Maybe Academy must inherit Person

Most of the time, subclassing is the wrong answer of a wrong question. You need to subclass when you want to extend or specialize behaviour of a class. A classical example would be:

class Animal:
    def noise(self):
        raise NotImplementedError # virtual method

class Duck(Animal):
    def noise(self):
        print("quack")

class Cat(Animal):
    def noise(self):
        print("meaw")

So in your case, you have a class person that implements show_data, and what you want is to extend the behaviour, for worker and student:

class Worker(Person): # a worker _is_ a person!
    def __init__(self, name, unit):
        # left as an exercise to the OP

    def show_data(self):
        # left as an exercise to the OP

class Student(Person):
    def __init__(self, name, promo):
        # left as an exercise to the OP

    def show_data(self):
        # left as an exercise to the OP

I won't get into much more details here, as I suppose you have a teacher you can ask more about the comments I made. But at least you tried, made some mistakes (AND MISTAKES ARE GOOD!). But I'm not giving you a full answer, my only goal here is to set you up in the right mind set to make your code a better design!

I hope this helps!

Sign up to request clarification or add additional context in comments.

6 Comments

Btw having Worker and Student as subclasses of Person is also bad design; those are roles, not subtypes. In fact you can be easily both at once.
@peter I sooo much agree with you, but then we might need to tell the OP's teacher that his exercise is stupid :-) And not all teacher take such criticism in a good way (yes, I used to criticize my teacher's exercises when I was at uni)
Well being able to criticize is skill like any other. Saying "This is stupid design" to the teacher would be also stupid, but asking "Why do you think it should be done this way?" or "Could this be modeled this way instead?" changes the conversation a lot.
Also I am actually a student and a worker, so you can't even model me. :(
You can then make a diamond inheritance :-D (or how to import C++ OOP insanity in Python :-p)
|
1

You want to be able to add people:

>>> academy = Academy()
>>> academy.add(Person('Pete'))
>>> academy.showAll()
Name: Pete

>>> academy.add(Student('Taras', 'Higher'))
>>> academy.showAll()
Name: Pete
Name: Taras, Education: Higher

>>> academy.add(Worker('riotburn', 'StackOverflow')
>>> academy.showAll()
Name: Pete
Name: Taras, Education: Higher
Name: riotburn, Workplace: StackOverflow

showAll needs to iterate over all people calling ShowData on them. This will be implemented differently for each type.

class Academy(object):
    def __init__(self):
        self.people = []

    def add(self, person):
        self.people.append(person)

    def showAll(self):
        for person in self.people:
            person.ShowData()

Where for example, Worker will implement ShowData as:

def ShowData(self):
    print 'Name: ' + self.name + ', Education:' + self.edu

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.