Как получить все значения переменных в классе?

class NiceClass():
    some_value = SomeObject(...)
    some_other_value = SomeOtherObject(...)

    @classmethod
    def get_all_vars(cls):
        ...

Я хочу, чтобы get_all_vars() возвращал [SomeObject(...), SomeOtherObject(...)], а точнее, значения переменных в cls.

Пробованные решения, которые не сработали для меня:

  • return [cls.some_value, cls.some_other_value, ...] (требуется указание переменной вручную)
  • создание подкласса Enum, а затем использование list(cls) (требуется использование some_value.value для доступа к значению в другом месте программы, также подсказка типа будет беспорядком)
  • namedtuples (нет, не касаясь этой темы, слышал, что это было намного сложнее, чем Enum)
  • [value for key, value in vars(cls).items() if not callable(value) and not key.startswith("__")] (слишком хакерский из-за использования vars(cls), также по какой-то причине он также включает get_all_vars из-за того, что это classmethod)

@ThierryLathuille не тот ответ, который я искал, но это решение моей проблемы, так что? все же хотелось бы решения этого вопроса

TNTzx 20.03.2022 13:04

Использование isinstance(value, classmethod) вместо callable(value) удалит get_all_vars из списка. Тем не менее, это не станет менее хакерским.

DeepSpace 20.03.2022 13:10
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
73
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это может звучать как https://xyproblem.info/, но мое решение может работать и в другом случае. Вы можете получить поля объекта, используя __dict__ или vars (что считается более питоническим: Словарь Python из полей объекта)

Вы можете сделать что-то вроде:

class ClassTest:
   def __init__(self):
      self.one = 1
      self.two = 2
list(vars(ClassTest()).values())

Но вы увидите, что у него есть некоторые ограничения. Он не распознает не определенные в self.variable_name переменные, как вы использовали выше. Тем не менее, это может вам помочь, потому что вы можете просто определить их в init.

OP уже знает о vars как о возможном решении, и в любом случае этот пример не отражает вариант использования OP.

DeepSpace 20.03.2022 13:10

Вы правы, но я все еще не уверен, почему это слишком хакерски. Поэтому я подумал, что это может помочь привести пример.

Natan 20.03.2022 13:12

@ Натан, это совсем не хакерство; Вот часть vars документации: With an argument, equivalent to object.__dict__, что означает, что это именно то его назначение.

Commissar Vasili Karlovic 20.03.2022 13:38

@CommissarVasiliKarlovic Я согласен. Спрашивающий не знает.

Natan 20.03.2022 14:11
Ответ принят как подходящий

Есть два способа. Это прямой ответ на ваш вопрос:

class Foo:
    pass


class Bar:
    x: int = 1
    y: str = 'hello'
    z: Foo = Foo()

    @classmethod
    def get_all(cls):
        xs = []
        for name, value in vars(cls).items():
            if not (name.startswith('__') or isinstance(value, classmethod)):
                xs.append(value)
        return xs

Вот что я предлагаю:

from dataclasses import dataclass, fields


class Foo:
    pass


@dataclass
class Bar:
    x: int = 1
    y: str = 'hello'
    z: Foo = Foo()

    @classmethod
    def get_defaults(cls):
        return [f.default for f in fields(cls)]

    @classmethod
    def get_all(cls):
        return [getattr(cls, f.name) for f in fields(cls)]

полученные результаты:

Bar.get_defaults() == Bar.get_all()
# True -> [1, 'hello', __main__.Foo]

Bar.x = 10
Bar.get_defaults() == Bar.get_all()
# False -> [1, 'hello', __main__.Foo] != [10, 'hello', __main__.Foo]

метод dataclass работает, первый тоже немного работает, хотя он не проверяет вызываемые объекты

TNTzx 20.03.2022 13:50

@TNTzx Я отредактировал dataclass. Пожалуйста, дайте ему чек

Commissar Vasili Karlovic 20.03.2022 13:53

понял, работает

TNTzx 20.03.2022 14:22

Вы можете создать список значений и, определить отдельные атрибуты одновременно с минимальным шаблоном.

class NiceClass():
    (some_value,
     some_other_value,
    ) = _all_values = [
        SomeObject(...),
        SomeOtherObject(...)
    ]
    

    @classmethod
    def get_all_vars(cls):
        return cls._all_values

Наиболее очевидным недостатком этого является то, что порядок имен и значений может легко рассинхронизироваться.

В идеале вы могли бы сделать что-то вроде

class NiceClass:

    _attributes = {
        'some_value': SomeObject(...),
        'some_other_value': SomeOtherObject(...)
    }

    @classmethod
    def get_all_vars(cls):
        return cls._attributes.values()

и иметь способ «внедрить» содержимое _attributes напрямую в пространство имен класса. Самый простой способ сделать это — смешанный класс, который определяет __init_subclass__:

class AddAttributes:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.__dict__.update(cls._attributes)


class NiceClass(AddAttributes):
    # As above
    ...

Другие вопросы по теме