Home > Software design >  Python dynamically import classes an call their functions
Python dynamically import classes an call their functions

Time:08-11

I have one Abstract Animal class.

from abc import ABC, abstractmethod


class Animal(ABC):  # Inherit from ABC(Abstract base class)
    @abstractmethod  # Decorator to define an abstract method
    def feed(self):
        pass

And three classes which Implements it

from Animal import Animal

class Lion(Animal):
   def feed(self):
        print("Feeding a lion with raw meat!")

from Animal import Animal

class Panda(Animal):
    def feed(self):
        print("Feeding a panda with some tasty bamboo!")
from Animal import Animal


class Snake(Animal):
    def feed(self):
        print("Feeding a snake with mice!")

Now I just want to import all classes, which are in the project folder and call the feed function of all classes, when there is a feed function.

from glob import glob
import os

if __name__ == '__main__':
   for file in glob(os.path.join(os.path.dirname(os.path.abspath(__file__)), "*.py")):
       name = os.path.splitext(os.path.basename(file))[0]
       # add package prefix to name, if required
       module = __import__(name)
       try:
            module.feed()
       except Exception as e:
            print(e)

My Problem is now, that I get the errors:

module 'Animal' has no attribute 'feed'

module 'Lion' has no attribute 'feed'

module 'main' has no attribute 'feed'

module 'Panda' has no attribute 'feed'

module 'Snake' has no attribute 'feed'

Can someone help me with this?

CodePudding user response:

I take it your files are called Snake.py, Panda.py etc. If so then you are invoking feed() on the files not the classes. You need to get the modules (which you've done), then get the class and then call the method:

from glob import glob
import os

if __name__ == '__main__':
   for file in glob(os.path.join(os.path.dirname(os.path.abspath(__file__)), "*.py")):
       name = os.path.splitext(os.path.basename(file))[0]
       if name == "Animal" or name == "main":  # avoid main.py and Animal.py
           continue
       # add package prefix to name, if required
       module = __import__(name)
       try:
           # get the class
           cls = getattr(module, name)
           # instantiate the class and call the method
           cls().feed()
       except Exception as e:
            print(e)

Ive also included a safety check to exclude main.py and Animal.py

  • Related