2017-02-19 22 views
2

Я пишу небольшое приложение на Python, который содержит несколько вложенных классов, как на пример ниже:python - как получить список внутренних классов?

class SuperBar(object): 
    pass 

class Foo(object): 
    NAME = 'this is foo' 

    class Bar(SuperBar): 
     MSG = 'this is how Bar handle stuff' 

    class AnotherBar(SuperBar): 
     MSG = 'this is how Another Bar handle stuff' 

Я использую вложенные классы для создания своего рода иерархии и обеспечить чистый способ реализации функций для парсера.

В какой-то момент я хочу создать список внутренних классов. Я хотел бы иметь следующий вывод:

[<class '__main__.Bar'>, <class '__main__.AnotherBar'>] 

Вопрос заключается в том: Какова рекомендуемый метод, чтобы получить список внутренних классов в вещих образом?

+0

1. Почему вы участвуете в занятиях, не могли бы вы дать больше контекста? 2. Разве вы просто не хотите, чтобы все подклассы «SuperBar» (в этом случае см. Http://stackoverflow.com/q/3862310/3001761)? – jonrsharpe

+0

Этого недостаточно. В фактическом приложении у меня больше корневых классов, таких как 'Foo', с большим количеством внутренних классов для завершения дерева синтаксического анализа. Мне также необходимо обеспечить, чтобы определенный токен, найденный (например, «Бар»), приходил в контексте корневого токена 'Foo'. Чтобы захватить эту иерархию, я использую эти внутренние классы. - спасибо –

+0

Тогда отредактируйте, чтобы больше контекста. Возможно, вы пытаетесь решить полностью неправильную проблему. – jonrsharpe

ответ

1

мне удалось получить список объектов внутреннего класса с описанным ниже методом:

import inspect 

def inner_classes_list(cls): 
    return [cls_attribute for cls_attribute in cls.__dict__.values() 
      if inspect.isclass(cls_attribute) 
      and issubclass(cls_attribute, SuperBar)] 

Он работает, но я не уверен, что при использовании __dict__ непосредственно хорошая вещь, чтобы сделать. Я использую его, потому что он содержит фактические class экземпляры, которые мне нужны и кажутся переносимыми через Python 2 и 3.

+0

Да - вы можете использовать __dict__ - это гораздо более распространенное место и полезно использовать с помощью вложенных классов. - но есть уловка, что, глядя на '__dict__', вы не видите атрибутов из суперклассов. Проверьте мой ответ. – jsbueno

1

Во-первых: я не вижу, как вложенные классы могут вам пригодиться. Как только у вас есть экземпляр f из Foo, вы понимаете, что f.Bar и f.AnotherBar будет одним и тем же объектом для всех экземпляров? То есть - вы не можете записать какой-либо атрибут, специфичный для f, на f.Bar, например f.Bar.speed - или он столкнется с атрибутом из другого экземпляра g.Bar.speed.

Чтобы преодолеть это и, фактически, единственное, что имеет смысл, вам нужно иметь экземпляры Bar и AnotherBar, прикрепленные к экземпляру f. Эти экземпляры обычно не могут быть объявлены в классе класса - вы должны создать их в своем методе Foo __init__.

Единственное, что могут сделать Bar и AntherBar: (1) иметь много классов и статических методов, то они работают только как пространства имен.

Или, если метаклассом для SuperBar или сами реализуют протокол дескриптора - https://docs.python.org/3/reference/datamodel.html#implementing-descriptors - но их, вы бы гораздо лучше, если superbar сам будет осуществлять дескриптор prootocol (при наличии либо __get__ или __set__ методы), и прилагается к Тело Foo у вас было бы экземпляров этих классов, а не самих классов.

Сказанное: вы пришли с решением использовать __dict__ для получения внутренних классов: это не сработает, если Foo сам наследует от других классов, которые также имеют вложенные классы. Суперклассы Foo никогда не искали. Вы можете иметь метод, либо посмотреть на все классы на Foo-х __mro__, или просто использовать dir и issubclass:

class Foo: 
    @classmethod 
    def inner_classes_list(cls): 
      results = [] 
      for attrname in dir(cls): 
       obj = getattr(cls, attrname) 
       if isinstance(obj, type) and issubclass(obj, SuperBar): 
        results.append(obj) 
      return results 

(Если вы хотите, чтобы это работало для всех классов, как Foo, который не разделяет общую базу, тот же код будет работать, если он не будет объявлен как метод класса, конечно, а также, SuperBar может быть параметром для этой функции, если у вас более одной иерархии вложенного класса.)

Теперь у вас есть это, мы просим вас задать другие вопросы, говоря, что вы хотите на самом деле - и прочитать о «дескрипторах» - и даже «свойствах». Действительно: очень мало пользы, которую можно придумать для вложенных подклассов.