Есть ли способ перечислить атрибуты класса без экземпляра объекта?
В Python 3.5, скажем, у меня есть:
class Foo:
def __init__(self, bar, barbar):
self.bar = bar
self.barbar = barbar
Я хочу получить список ["bar", "barbar"]
из класса.
Я знаю, что могу:
foo = Foo(1, 2)
foo.__dict__.keys()
Есть ли способ получить ["bar", "barbar"]
без, создавая экземпляр объекта?
Ответы
Ответ 1
Нет, поскольку атрибуты являются динамическими (так называемые атрибуты экземпляра). Рассмотрим следующее:
class Foo:
def __init__( self ):
self.bar = 1
def twice( self ):
self.barbar = 2
f = Foo()
print( list(f.__dict__.keys() ) )
f.twice()
print( list(f.__dict__.keys() ) )
В первой печати было установлено только f.bar
, чтобы были доступны только атрибуты, отображаемые при печати ключей атрибута. Но после вызова f.twice()
вы создаете новый атрибут f
, и теперь его печать показывает как bar
, так и barbar
.
Ответ 2
Предупреждение -
Следующее не является надежным, всегда обеспечивая 100% правильные данные. Если в вашем __init__
вы получите что-то вроде self.y = int(1)
, вы в конечном итоге включите int
в свою коллекцию атрибутов, что не является желаемым результатом для ваших целей. Кроме того, если вы добавляете динамический атрибут где-то в свой код, например Foo.some_attr = 'pork'
, то вы никогда не увидите этого. Имейте в виду, что именно вы проверяете, в какой точке вашего кода, и понимаете, почему у вас есть и нет этих включений в вашем результате. Вероятно, есть и другие "поломки", которые не дадут вам полного 100% ожидания того, что все атрибуты, связанные с этим классом, но, тем не менее, следующее должно дать вам то, что вы, возможно, ищете.
Однако я настоятельно рекомендую вам обратиться к другим ответам здесь, а дубликат, который был помечен, объясняет, почему вы не можете/не должны этого делать.
Ниже приведена форма решения, с которой вы можете попробовать:
Я разберусь с ответом inspect
.
Тем не менее, я задаю вопрос (и, возможно, совет) против того, чтобы делать что-то подобное в готовом к производству коде. В целях расследования, конечно, выбивай себя.
Используя модуль inspect, как указано уже в одном из других ответов, вы можете использовать getmembers, который затем можно перебирать через атрибуты и проверять соответствующие данные, которые вы хотите исследовать.
Например, вы задаете вопросы динамическим атрибутам в __init__
Поэтому мы можем привести этот пример, чтобы проиллюстрировать:
from inspect import getmembers
class Foo:
def __init__(self, x):
self.x = x
self.y = 1
self.z = 'chicken'
members = getmembers(Foo)
for member in members:
if '__init__' in member:
print(member[1].__code__.co_names)
Ваш вывод будет кортежем:
('x', 'y', 'z')
В конечном счете, по мере того, как вы проверяете класс Foo
, чтобы получить его члены, есть атрибуты, которые вы можете продолжить исследовать по мере повторения каждого члена. Каждый член имеет атрибуты для дальнейшей проверки и т.д. В этом конкретном примере мы сосредоточимся на __init__
и проверим __code__
(для каждого документа: объект __code__
, представляющий тело скомпилированной функции), атрибут которого имеет атрибут co_names
, который предоставляет кортеж членов, как указано выше с выходом запуска кода.
Ответ 3
Как упоминал Ларне, атрибуты, объявленные внутри функций (например, __init__
), являются динамическими. Они фактически не существуют до тех пор, пока не будет вызвана функция __init__
.
Однако есть способ сделать то, что вы хотите.
Вы можете создавать атрибуты класса, например:
class Foo:
bar = None
barbar = None
def __init__(self, bar, barbar):
self.bar = bar
self.barbar = barbar
И вы можете получить доступ к таким атрибутам, как это:
[var for var in vars(Foo).keys() if not var.startswith('__')]
Что дает этот результат:
['bar', 'barbar']