Подтвердить что ты не робот

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

В 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"] без, создавая экземпляр объекта?

4b9b3361

Ответ 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']