Как перебрать каждое объявление класса, произошедшее от определенного базового класса? - PullRequest
4 голосов
/ 22 января 2012

Я бродил, как elixir \ sqlalchemy узнает все классы сущностей, которые я объявил в моей модели, когда я вызываю setup_all()? Мне нужна такая функциональность в моем маленьком проекте, но я понятия не имею. Я попытался пройти через setup_all() эликсира и обнаружил, что он хранит коллекцию всех классов сущностей в «глобальном» списке (или это было правильно?), Но я не могу уловить момент, когда список заполнены. Есть идеи?

Ответы [ 2 ]

9 голосов
/ 22 января 2012

Для определений классов это проще (без импорта)

def find_subclasses(cls):
    results = []
    for sc in cls.__subclasses__():
        results.append(sc)
    return results

Я не уверен, хотели ли вы это или объекты.Если вы хотите объекты:

import gc

def find_subclasses(cls):
    results = []
    for sc in cls.__subclasses__():
        for obj in gc.get_objects():
            if isinstance(obj, sc):
               results.append(obj)
    return results
4 голосов
/ 22 января 2012

Отвечая на главный вопрос, вообще не разбираясь с SQLALchemy или elixir - да, это возможно в Python.

Модуль сборщика мусора (gc) в стандартной библиотеке имеет вызов функции, который позволяет получить все ссылки на данный объект в интерпретаторе. Класс всегда упоминается в атрибуте __mro__ любого унаследованного класса.

Итак, следующая функция может извлечь все классы, которые наследуются от данного класса:

import gc
def find_subclasses(cls):
    all_refs = gc.get_referrers(cls)
    results = []
    for obj in all_refs:
        # __mro__ attributes are tuples
        # and if a tuple is found here, the given class is one of its members
        if (isinstance(obj, tuple) and
            # check if the found tuple is the __mro__ attribute of a class
            getattr(obj[0], "__mro__", None) is obj):
            results.append(obj[0])
    return results
...