Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exchange some component class methods for class attributes #593

Open
mfranz13 opened this issue Jan 18, 2024 · 0 comments
Open

Exchange some component class methods for class attributes #593

mfranz13 opened this issue Jan 18, 2024 · 0 comments

Comments

@mfranz13
Copy link
Contributor

Inside of the component classes are class methods like table_name(), internal_node_name() or active_identifier() that return just one thing (e.g. the string "pipe") with no other functionality to the method itself.
In the abstract classes of the components raise these functions a NotImplementedError.

Following UseCase:
I want to get all table names of all branch components ("pipe", "pump", ...), not only those in my net object, but of all branch components pandapipes has implemented. The most simple way would be to create a function and hardcorde the table names into some sort of container like a list. When additional components are added, one would have to update the list with the new component, which is not ideal.
Fortunately, pandapipes implemented the components into a class structure which has stuff like the table name already implemented in the class.
But how do i now get all table names of the branch components?
All branch components are child classes of the class BranchComponent. So i could use the subclasses() method and create a function like this:

def get_all_subclasses(cls):
        all_subclasses = list()
        for subclass in cls.__subclasses__():
            all_subclasses.append(subclass)
            all_subclasses.extend(get_all_subclasses(subclass))
        return all_subclasses

and call it like so:

 all_branch_components = get_all_subclasses(BranchComponent)

Now i have all my branch component classes. But i also have some abstract classes like BranchWZeroLengthComponent, which has no table name. So i have to iterate over the classes.

And this is where only using class methods gets inconveniend. How do i check if my component is a component with a table name? With the current implementation i would need to iterate over each subclass, call the table_name() method and catch the occuring NotImplementedErrorin a try except block. The code could look like this:

 filtered = list()
 for bc in all_branch_components:
        try:
            bc.table_name()
            filtered.append(bc)
        except Exception as e:
            logging.info(f"branch component {bc} has no table name {e}")

Wouldn't it be better to implement class attributes instead of class methods for the functions that only return something? That way the code would reduce to the follwing with no try except block.

for bc in all_branch_components:
       if hasattr(bc, "table_name"):
              filtered.append(bc)

The parent classes simply do not define the class attribute, which would raise an AttributeError if tried to be called. Child classes inheriting from a class with a class attribute will overwrite the class attribute for the child class. The attribute in the parent class will stay the same.

class A:
    table_name = None

    @classmethod
    def results(cls):
        # do something
        cls.table_name
        # do something

class B(A):
    table_name = "BClass"

class C(B):
    table_name = "Class"

class D(B):
    @classmethod
    def do_something(cls):
        pass

class E(C):
    @classmethod
    def do_something(cls):
        pass

print(D.table_name) --> "BClass"
print(E.table_name) --> "CClass"

There is still a minor problem:
The abstract classes use the attribute in some of their methods (in this example the results method). None could be non-fitting or producing some sort of silent Error.
Not implementing the class attribute in the A-Class will produce the same output as before, but the code line will be highlighted due to the unreferenced table_name in the abstract method. But when the class attribute gets wrongly called for the abstract class, an AttributeError is raised, which would be preferable over the initialisation with None.

Another totally different approach would be to get rid of the class structure and implement the components with modules. Inheritance would translate to importing from another module.
It could look something like this for the BranchComponent where the class itself would be translated to the module BranchComponent.py (at the moment, each class has its own module anyway):

import component
component.init_results()

What do you think about this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant