Есть ли способ перечислить атрибуты класса без создания объекта?

В 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 который предоставляет кортеж членов, как указано выше, с выводом выполнения кода.

Попробуйте имя класса.аннотации.keys()

Как упоминал Лёрн, атрибуты, объявленные внутри функций (например, __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']
Другие вопросы по тегам