Самоанализ Python:Как получить «несортированный» список атрибутов объекта?
-
11-07-2019 - |
Вопрос
Следующий код
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, нет - не *.Это связано с тем, что все атрибуты класса хранятся в словаре (который, как вы знаете, неупорядочен).
*:на самом деле это возможно, но для этого потребуются либо декораторы, либо, возможно, взлом метакласса.Что-то из этого вас интересует?
Я не пытаюсь быть бойким, но возможно ли вам организовать классы в исходном коде в алфавитном порядке?Я считаю, что когда в одном файле много классов, это может быть полезно само по себе.