Есть ли способ перечислить атрибуты класса без создания объекта?
В 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"]
без создания объекта?
4 ответа
Нет, потому что атрибуты являются динамическими (так называемые атрибуты экземпляра). Рассмотрим следующее,
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
,
Предупреждение. Следующее не является надежным, поскольку всегда обеспечивает 100% правильные данные. Если у вас будет что-то вроде self.y = int(1)
в вашем __init__
, вы в конечном итоге в том числе int
в вашей коллекции атрибутов, что не является желаемым результатом для ваших целей. Кроме того, если вам случится добавить динамический атрибут где-то в вашем коде, как Foo.some_attr = 'pork'
тогда вы тоже никогда этого не увидите. Помните о том, что именно вы проверяете в каком месте вашего кода, и понимайте, почему у вас есть эти включения в вашем результате, а какие нет. Возможно, есть и другие "поломки", которые не дадут вам 100% -ного ожидания того, что все атрибуты связаны с этим классом, но, тем не менее, следующее должно дать вам то, что вы, возможно, искали.
Тем не менее, я настоятельно рекомендую вам воспользоваться другими ответами здесь и помеченным дубликатом, который объясняет, почему вы не можете / не должны этого делать.
Следующее является формой решения, с которым вы можете попытаться возиться:
Я буду расширяться на 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
который предоставляет кортеж членов, как указано выше, с выводом выполнения кода.
Как упоминал Лёрн, атрибуты, объявленные внутри функций (например, __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']