Самоанализ Python: как получить «несортированный» список атрибутов объекта? - PullRequest
4 голосов
/ 13 марта 2009

следующий код

import types
class A:
    class D:
        pass
    class C:
        pass
for d in dir(A):
    if type(eval('A.'+d)) is types.ClassType:
        print d

выходы

C
D

Как мне заставить его выводить в порядке, в котором эти классы были определены в коде? * 1007 Т.е. *

D
C

Есть ли другой способ, кроме использования inspect.getsource (A) и его анализа?

Ответы [ 5 ]

8 голосов
/ 13 марта 2009

Обратите внимание, что этот анализ уже сделан для вас в проверке - посмотрите на inspect.findsource, который ищет в модуле определение класса и возвращает номер источника и номер строки. Сортировка по этому номеру строки (вам также может потребоваться разделить классы, определенные в отдельных модулях) должна дать правильный порядок.

Однако эта функция, похоже, не документирована, а просто использует регулярное выражение для поиска строки, поэтому она не может быть слишком надежной.

Другим вариантом является использование метаклассов или какой-либо другой способ неявного или явного упорядочения информации для объекта. Например:

import itertools, operator

next_id = itertools.count().next

class OrderedMeta(type):
    def __init__(cls, name, bases, dct):
        super(OrderedMeta, cls).__init__(name, bases, dct)
        cls._order = next_id()

# Set the default metaclass
__metaclass__ = OrderedMeta

class A:
    class D:
        pass
    class C:
        pass

print sorted([cls for cls in [getattr(A, name) for name in dir(A)] 
           if isinstance(cls, OrderedMeta)], key=operator.attrgetter("_order"))

Однако это довольно навязчивое изменение (требует установки метакласса всех интересующих вас классов в OrderedMeta)

5 голосов
/ 13 марта 2009

Нет, вы не можете получить эти атрибуты в порядке, который вы ищете. Атрибуты Python хранятся в формате dict (читай: hashmap), который не знает о порядке вставки.

Кроме того, я бы избегал использования eval, просто сказав

if type(getattr(A, d)) is types.ClassType:
    print d

в вашем цикле. Обратите внимание, что вы также можете просто перебирать пары ключ / значение в A.__dict__

4 голосов
/ 13 марта 2009

Модуль inspect также имеет функцию findsource. Возвращает кортеж исходных строк и номер строки, в которой определен объект.

>>> import inspect
>>> import StringIO
>>> inspect.findsource(StringIO.StringIO)[1]
41
>>>

Функция findsource фактически ищет в исходном файле и ищет вероятных кандидатов, если ему дан объект класса.

Учитывая метод, функцию, трассировку, фрейм или объект кода, он просто смотрит на атрибут co_firstlineno (содержащегося) объекта кода.

1 голос
/ 13 марта 2009

AFAIK, нет - нет *. Это потому, что все атрибуты класса хранятся в словаре (который, как вы знаете, неупорядочен).

*: это на самом деле возможно, но это потребует либо декораторов, либо, возможно, взлома метакласса Вас что-нибудь интересует?

0 голосов
/ 13 марта 2009

Я не пытаюсь быть легкомысленным, но возможно ли для вас организовать классы в вашем источнике по алфавиту? я считаю, что если в одном файле много классов, это может быть полезно само по себе.

...