2016-08-01 6 views
0

Я написал метакласс, который автоматически регистрирует свои классы в dict во время выполнения. Чтобы он работал правильно, он должен уметь игнорировать абстрактные классы.Как определить, является ли класс абстрактным в Python 3?

код работает очень хорошо в Python 2, но я запустить в стену, пытаясь сделать его совместимым с Python 3.

Вот что код выглядит в настоящее время:

def AutoRegister(registry, base_type=ABCMeta): 
    class _metaclass(base_type): 
     def __init__(self, what, bases=None, attrs=None): 
      super(_metaclass, self).__init__(what, bases, attrs) 

      # Do not register abstract classes. 
      # Note that we do not use `inspect.isabstract` here, as 
      # that only detects classes with unimplemented abstract 
      # methods - which is a valid approach, but not what we 
      # want here. 
      # :see: http://stackoverflow.com/a/14410942/ 
      metaclass = attrs.get('__metaclass__') 
      if not (metaclass and issubclass(metaclass, ABCMeta)): 
       registry.register(self) 

    return _metaclass 

Использование в Python 2 выглядит следующим образом:

# Abstract classes; these are not registered. 
class BaseWidget(object): __metaclass__ = AutoRegister(widget_registry) 
class BaseGizmo(BaseWidget): __metaclass__ = ABCMeta 

# Concrete classes; these get registered. 
class AlphaWidget(BaseWidget): pass 
class BravoGizmo(BaseGizmo): pass 

Что ча не выяснять, однако, как это сделать в Python 3.

Как метакласс определить, если он инициализирует абстрактный класс в Python 3?

+0

Несмотря на использование 'ABCMeta', ваши якобы« абстрактные »классы в коде Python 2, который вы показываете, на самом деле не абстрактны (т. Е. Вы можете создавать экземпляры, если хотите, и Python не будет создавать исключение). Чтобы что-то действительно было абстрактным, вам нужно использовать декоратор '@ abstractmethod' для некоторых методов, которые вы заявляете в нем. Классы для детей также будут абстрактными, если они не переопределяют эти методы (без использования самих декораторов). Я не уверен, что здравый ответ можно ответить на ваш вопрос, не исправляя этот фундаментальный вопрос в первую очередь. – Blckknght

+0

Я ценю вход. Ваш комментарий побудил меня продолжить некоторые исследования, и теперь я вижу, что мое первоначальное понимание «абстрактного» было неправильным. Мне нужно подумать об этом; мы часто используем этот шаблон в нашей кодовой базе, но если мы в конечном счете используем инструмент не по-другому, это вызовет серьезные проблемы в долгосрочной перспективе. – user5568265

ответ

0

PEP3119 описывает, как ABCMeta метакласса «метки» абстрактные методы и создает __abstractmethods__ frozenset, который содержит все методы класса, которые до сих пор абстрактным. Итак, чтобы проверить, является ли класс cls абстрактным, проверьте, является ли cls.__abstractmethods__ пустым или нет.

Я также нашел this relevant post on abstract classes Полезно.