Python: find classes in a module before class definition

I have a python class in a module, and I have several methods in it that should have a list of some other classes in one module. Here's how I do it right now:

module.py

class Main:
  @staticmethod
  def meth1():
    for c in classes:
      #do something

  @staticmethod
  def meth2():
    for c in classes:
      #do something

class Class1:
  pass

class Class2:
  pass

class Class3:
  pass

classes = [Class1, Class3]

A few things I would like to improve:

  • I would like the list to classesbe somewhere more common. Ideally, either outside of all classes, or at the top of the module file, or as an attribute of a class Main, but outside of either meth1, or meth2. The purpose of this is to simplify the search if someone needs to add another class definition.
  • , , . # 1 ( , ). , . , , dir() locals(), , . , - , . , , .

?

+4
5

decorator, . , , .

:

# Classes are added here if they are important, because...
important_classes = []


def important(cls):
    important_classes.append(cls)
    return cls


@important
class ClassA(object):
    pass


class ClassB(object):
    pass


@important
class ClassC(object):
    pass

# Now you can use the important_classes list however you like.
print(important_classes)
# => [<class '__main__.ClassA'>, <class '__main__.ClassC'>]
+4

.

:

local_vars = locals().values()

:

import inspect
local_vars = [i for i in local_vars if inspect.isclass(i)]

, , cls.__module__ == __name__ :

def get_classes():
    global_vars = list(globals().values())
    classes = [i for i in global_vars if inspect.isclass(i)]
    return [i for i in classes if i.__module__ == __name__]

: inspect , . , , , , cls.__module__ == __name__.

, Python3 list(globals().values(), . Python2, dict.values() , .

EDIT:

, . , .

def get_classes(name='target'):
    global_vars = list(globals().values())
    classes = [i for i in global_vars if inspect.isclass(i)]
    return [i for i in classes if hasattr(i, name)]
+2

, , __subclasses__(), :

class Main:
    def meth1(self):
        for c in Holder._subclasses__():
            #do something

    def meth2(self):
        for c in Holder._subclasses__():
            #do something

class Holder(object):
    pass

class Class1(Holder):
    pass

class Class2(Holder):
    pass

class Class3(Holder):
    pass

Main, , class:

class Main(object):
    @classmethod
    def meth1(cls):
        for c in cls._subclasses__():
            #do something

class Class1(Main): pass

You need to inherit from objectusing Python 2 for this to work.

+2
source

Your list seems to be aimed at a subset of the available classes in the module, so at some point you will need to specify the classes you are targeting.

import sys

target_classes = ["Class1", "Class3"]

class Main:
    def __init__(self, classes):
        self.target_classes = classes

    def meth1(self):
        for s in self.target_classes:
            C = getattr(sys.modules[__name__], s)
            C().speak()

    def meth2(self):
        for c in classes:
            print c
            #do something

class Class1:
    def speak(self):
        print "woof"

class Class2:
    def speak(self):
        print "squeak"

class Class3:
    def speak(self):
        print "meow"


Main(target_classes).meth1()

--output:--
woof
meow
+2
source

I'm not sure if this is the best practice, but it will do what you need:

class Main:
    def __init__(self, locals):
        self.classes = []
        for (c, val) in locals.iteritems():
            try:
                if c[:5] == 'Class':
                    self.classes.append(val)
            except:
                pass

    def meth1(self):
        for c in self.classes:
            pass

    def meth2(self):
        for c in self.classes:
            pass

class Class1:
    pass

class Class2:
    pass

class Class3:
    pass

main = Main(locals())
print main.classes
+1
source

All Articles