0

I am new to Python and I have prior experience in VBA. I wish to create Classes in Python such that I could achieve the following syntax:

Company('MS').Department('Finance').Employee('John').FullName = 'John MacDonalds'
Company('MS').Department('Finance').Employee('John').Wages = '5000'

I am beginning to realize that declaring the Class structure in Python is very different from VBA.

Am I on the right approach? If not, will there be any other recommended approach for this Parent/Child structure?

martineau
  • 99,260
  • 22
  • 139
  • 249
FlyFly Wing
  • 79
  • 1
  • 8
  • Naming conventions of methods aside, you are roughly on the right track. You could check out online tutorials of how OOP works in Python. – Julian Chan Dec 23 '19 at 09:25
  • this is possible if you have a class `Company` which has a method `Department` that returns an object that has the next item in the chain.... you can put all of this into one class and always return `self` but i dont think this is what you want to do. what are you trying to make? if its a database-like thing did you consider dictionaries? pandas DataFrames? – Nullman Dec 23 '19 at 09:25

2 Answers2

0

I really don't think that's a good use of inheritance. Good inheritance is when the child class can easily be substituted for the parent class with no difficulties. Is an employee substitutable for a department? That doesn't seem right. Wouldn't a department be able to do tons of things an employee couldn't? For every function you have for a department that an employee can't do, you would have to have a "throw new not implemented" in the child class.

This is known as the Liskov Substitution Principle. Basically subclasses must be substitutable for their base classes. My favorite example is with birds and penguins. You could make a bird class and have lots of different kinds of birds inherit from this class. But what happens when you create a penguin class inheriting from bird? Penguins can't fly but birds can. So in the penguin class, you would implement this function and would have to say "throw new not implemented." Its not good because if you put a penguin in where a function is expecting a bird, it will freak out and crash when you give it a penguin.

I hope that helps. I'm not too familiar with Python specifically but I do understand inheritance.

user3308807
  • 15
  • 1
  • 7
0

You haven't really said what the syntax you want is supposed to accomplish which would be useful to know...

Nesting classes as shown below would allow you to achieve the syntax you want, but the result is not only very "unpythonic" — it's also completely useless and I can't think a reasonable way to implement to change that.

Without more information about what you're doing, at the moment I can think of an alternative to suggest. I suggest you just create a bunch of regular non-nested classes and explicitly instantiate them when needed.

Note that I've changed the names you were to follow the PEP 8 naming conventions.

class Company:
    def __init__(self, name):
        self.name = name

    class Department:
        def __init__(self, dept_name):
            self.dept_name = dept_name

        class Employee:
            def __init__(self, given_name):
                self.given_name = given_name


Company('MS').Department('Finance').Employee('John').full_name = 'John MacDonalds'

Here's a way to implement your tree structure via Python "autovivification" using the Vividict dictionary defined in this answer.

I've adapted it to support different Vividict subclasses at each level in the hierarchy: i.e. Company, Department, and Employee. Each subclass defines a class atribute named subtype the the Vividict base class' __missing__() will use when creating missing key values. I also added __repr__() method to each one to make instance print out all the items they contain.

This is just a proof-of-concept and I really don't know if you can use it or not, but it should give you a good idea of one way of doing what you want with some fairly readable syntax.

class Vividict(dict):  # Base class.
    subtype = dict
    def __missing__(self, key):
        value = self[key] = self.subtype(key)
        return value

class Employee:  # Leaf - Regular class
    def __init__(self, given_name):
        self.given_name = given_name
    def __repr__(self):
        return f'{self.__class__.__name__}({self.given_name!r})'

class Department(Vividict):  # Branch.
    subtype = Employee
    def __init__(self, dept_name):
        self.dept_name = dept_name
    def __repr__(self):
        return (f'{self.__class__.__name__}({self.dept_name!r})' + '\n    '
                + repr(list(self.values())))

class Company(Vividict):  # Root of tree.
    subtype = Department
    def __init__(self, co_name):
        self.co_name = co_name
    def __repr__(self):
        return (f'{self.__class__.__name__}({self.co_name!r})' + '\n  '
                + repr(list(self.values())))

company = Company('MS')
company['Finance']['George'].full_name = 'George Brown'
company['Finance']['Mary'].full_name = 'Mary Jones'
print(company)

Output:

Company('MS')
  [Department('Finance')
    [Employee('George'), Employee('Mary')]]
martineau
  • 99,260
  • 22
  • 139
  • 249
  • Thanks for the reply. What I am really trying to do is this. There is a **tree structure** that I need to follow. So I am trying to create a class Company that stores a few departments and departments a few Employees. When I used VBA, I created the 3 classes that use dictionary to store the Child Object. So the final syntax will appear to be the one that I have shown above. Do you have some better suggestions to model this **Tree Structure**? – FlyFly Wing Dec 23 '19 at 13:40
  • You can implement classes with dictionaries in Python, too. You just can't use the syntax you proposed. A very "pythonesque" way to implement a tree structure is to use nested dictionaries. You could build a tree by manually creating and adding objects to instances of the classes. There's even a cute way to make building them automatic (via [autovivification](https://en.wikipedia.org/wiki/Autovivification)) which has very nice syntax. See [What is the best way to implement nested dictionaries?](https://stackoverflow.com/questions/635483/what-is-the-best-way-to-implement-nested-dictionaries) – martineau Dec 23 '19 at 14:00
  • Thanks for updating the post. I was about to ask you how to separate the classes in order to map into the dictionary. :D – FlyFly Wing Dec 25 '19 at 06:08
  • To be honest, I wasn't sure how the `Vividict` approach would work if you want to have different classes as the various levels — so decided to give it a shot. If you liked my answer please consider accepting and possibly up-voting it. See [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – martineau Dec 25 '19 at 08:55