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
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
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):
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:
and call it like so:
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:
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.
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.
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):
What do you think about this?