2014-06-15 6 views
2

У меня есть иерархия классов, которую я хочу зарегистрировать, чтобы впоследствии получить доступ к ней. До сих пор я делал это вручную:Как запустить код при оценке класса Python

class FirstClass(MyBaseClass): 
    .... 
registry.register(FirstClass) 

class SecondClass(FirstClass): 
    .... 
registry.register(SecondClass) 

Я ищу способ позвонить registry.register(Class), когда класс вычисляется (то есть, когда кто-то импортирует пакет с классом), без вызова это явно.

Наверное, мне нужно что-то добавить к MyBaseClass, но я не мог понять, что. Все специальные методы, по-видимому, связаны между собой, а не связаны с классом.

Есть ли способ сделать это?

Пояснение: Реестр отслеживает классы, полученные из BaseClass. В какой-то момент кода я просматриваю все эти классы и создаю объекты. Это немного сложнее, потому что реестр тоже делает другие вещи, но это основная идея.

+1

Просто небольшая точка, но то, что вы хотите, когда оценивается класс, не тогда, когда его объявили (объявленное только один раз, когда вы пишете Это). –

+0

можете ли вы поделиться еще немного кода? что такое реестр, где он объявлен и что он делает? – timgeb

+0

@Бурхан Халид - спасибо, я исправил формулировку. – zmbq

ответ

2

Это точно метаклассы предназначены для: применить операцию по всей иерархии классов:

In [1]: def register(cls): 
    ...:  # just to show when it is called. 
    ...:  print('Register: {}'.format(cls)) 
    ...: 
    ...: 
    ...: class MyMeta(type): 
    ...:  def __new__(cls, name, bases, attrs): 
    ...:   the_cls = super().__new__(cls, name, bases, attrs) 
    ...:   register(the_cls) 
    ...:   return the_cls 

In [2]: class FirstClass(metaclass=MyMeta): 
    ...:  pass 
    ...: 
Register: <class '__main__.FirstClass'> 
In [3]: class SecondClass(FirstClass): 
    ...:  pass 
    ...: 
Register: <class '__main__.SecondClass'> 

Заметим, что вы должны добавить метакласса только в корне иерархии, и это будет унаследованный во всех дочерних классах, поэтому вам нужно просто добавить его для MyBaseClass, и все готово.

Для углубленного объяснения см это так вопрос: What is a metaclass in Python?


я использовал синтаксис python3. В python2 добавить метакласса вы должны установить атрибут __metaclass__:

class MyClass(object): 
    __metaclass__ = MyMeta 

я хотел бы отметить, что для получения подклассы класса вы можете использовать метод __subclasses__. Там нет необходимости следить за ними в явном виде, а не использовать метакласса:

In [4]: FirstClass.__subclasses__() 
Out[4]: [__main__.SecondClass] 
+0

Металлассы! Python определенно правит. – zmbq

0

У моего недавнего проекта было требование отслеживать классы, и мой первоначальный подход состоял в том, чтобы использовать globals() или что-то в этом роде для поиска классов, однако pythonistas на irc.freenode.org #python предложил использовать такие декораторы, как этот, и это выглядит действительно вещий:

registry = {} 
def registered(cls): 
    registry[cls.__name__] = cls 
    return cls 

@registered 
class Foo: 
    """ 
    """ 
@registered 
class Bar: 
    """ 
    """ 

при импорте этого файла, file.registry будет иметь все классы внутри него, и вы кал посмотреть его с реестром [ «cLASS_NAME»]. В нашем случае мы выбрали нашу реализацию класса на основе настроенного класса Class_Name.

+0

Это похоже на мой оригинальный подход. Проблема в том, что иногда я (или другие пользователи библиотеки) забываю, и это приводит к ненужным ошибкам. – zmbq

2

Python автоматически отслеживает непосредственных подклассов любых новых классов (классы с object в качестве базового класса или основания класс, полученный таким образом) определяют в атрибуте класса с именем __subclasses__. Это означает, что вам не нужно вручную регистрировать их самостоятельно.

Чтобы получить целую иерархию наследования, вам нужно будет собрать то, что в атрибуте для каждого подкласса рекурсивно.Это то, что я имею в виду:

class MyBaseClass(object): pass 
class FirstClass(MyBaseClass): pass 
class SecondClass(FirstClass): pass 

def get_subclasses(cls): 
    return cls.__subclasses__() + [g for s in cls.__subclasses__() 
            for g in get_subclasses(s)] 

print(get_subclasses(MyBaseClass)) 

Выход:

[<class '__main__.FirstClass'>, <class '__main__.SecondClass'>] 
Смежные вопросы