Самоанализ Python:Как получить «несортированный» список атрибутов объекта?

StackOverflow https://stackoverflow.com/questions/640479

Вопрос

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

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

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

D
C

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

Это было полезно?

Решение

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

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

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

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

Другие советы

Обратите внимание, что этот синтаксический анализ уже выполнен за вас при проверке — взгляните на 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).

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

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

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

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

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

*:на самом деле это возможно, но для этого потребуются либо декораторы, либо, возможно, взлом метакласса.Что-то из этого вас интересует?

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top