3
\$\begingroup\$

I'm working on a project which due to the complexity of the business logic has had to pull out some classes to do computation related to some values in a database. To link the code and database, both when inserting and selecting, I need to get a list of all the class names contained within a single file. It works for me, but is this a sane approach?

import inspect

import my_module

my_module_class_names = [
    name for name, clazz in inspect.getmembers(my_module, inspect.isclass)
    if clazz.__module__ == my_module.__name__
]
  • inspect.getmembers(my_module, inspect.isclass) gets any class members of my_module.
  • if clazz.__module__ == my_module.__name__ ensures that classes imported into my_module are excluded from the list. This is the main reason I'm asking for a review - I only thought to include this clause because I had already imported other classes, and therefore the list had extraneous members.

Alternatively, from within my_module:

import inspect
import sys

def class_names() -> List[str]:
    return [
        name for name, clazz in inspect.getmembers(sys.modules[__name__], inspect.isclass)
        if clazz.__module__ == sys.modules[__name__].__name__
    ]
\$\endgroup\$
3
\$\begingroup\$

I have already used similar code and it looks rather fine. Some nitpicks:

  • I’d name the variable cls to mimic the name often used as first parameters of @classmethods; or class_ as it is more common;
  • I’d store a list of classes intead of a list of names, this feels more directly usable (and names are still stored as cls.__name__ if need be);
  • sys.modules[__name__].__name__ should be just __name__.

Alternatively, since these classes seems related to each other, you may have an inheritance tree; or maybe a common base class. In this case, you could be even more specific using something such as:

[cls for _, cls in inspect.getmembers(my_module, inspect.isclass) if issubclass(cls, my_module.CommonBase)]

or

my_module.CommonBase.__subclasses__()

if there really is a single level of inheritance, but I wouldn't count much on it as it can break so easily.

\$\endgroup\$
  • \$\begingroup\$ Excellent! I do need the actual class names rather than the types, and I don't have a class hierarchy, but this can serve as basically a recipe for anyone who wants either variant of this pattern. \$\endgroup\$ – l0b0 Jan 10 at 18:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.