简体   繁体   English

如何获取class中变量的所有值?

[英]How to get all values of variables in class?

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

    @classmethod
    def get_all_vars(cls):
        ...

I want get_all_vars() to return [SomeObject(...), SomeOtherObject(...)] , or more specifically, the values of the variables in cls .我希望get_all_vars()返回[SomeObject(...), SomeOtherObject(...)] ,或者更具体地说,返回cls中变量的值。

Solutions tried that didn't work out for me:尝试过的解决方案对我没有用:

  • return [cls.some_value, cls.some_other_value, ...] (requires listing the variable manually) return [cls.some_value, cls.some_other_value, ...] (需要手动列出变量)
  • subclassing Enum then using list(cls) (requires using some_value.value to access the value elsewhere in the program, also type hinting would be a mess)子类化Enum然后使用list(cls) some_value.value
  • namedtuples (nope not touching that subject, heard it was much more complicated than Enum ) namedtuples(不涉及那个主题,听说它比Enum复杂得多)
  • [value for key, value in vars(cls).items() if not callable(value) and not key.startswith("__")] (too hacky due to using vars(cls) , also for some reason it also includes get_all_vars due to it being a classmethod ) [value for key, value in vars(cls).items() if not callable(value) and not key.startswith("__")] (由于使用vars(cls)太老套了,也出于某种原因它还包括get_all_vars因为它是一个classmethod

There are two ways.有两种方法。 This is a straight answer to your question:这是对您问题的直接回答:

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

This is what I suggest:这就是我的建议:

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)]

results:结果:

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]

You can create a list of values and define individual attributes at the same time with minimal boilerplate.您可以使用最少的样板同时创建一个值列表定义各个属性。

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

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

The most obvious drawback to this is that it's easy to get the order of names and values out of sync.这样做最明显的缺点是很容易使名称和值的顺序不同步。

Ideally, you might like to do something like理想情况下,您可能想做类似的事情

class NiceClass:

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

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

and have some way to "inject" the contents of _attributes into the class namespace directly.并有办法将_attributes的内容直接“注入”到 class 命名空间中。 The simplest way to do this is with a mix-in class that defines __init_subclass__ :最简单的方法是使用定义 __init_subclass__ 的混合__init_subclass__

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


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

This might sound like a https://xyproblem.info/ but my solution might work in the other case as well.这可能听起来像https://xyproblem.info/但我的解决方案也可能适用于其他情况。 You can get the fields of an object by using __dict__ or vars (which is considered more pythonic given: Python dictionary from an object's fields )您可以使用__dict__vars获取 object 的字段(考虑到更多 pythonic: Python dictionary from an object's fields

You could do something like:你可以这样做:

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

But you will see that it has some limitations.但是您会发现它有一些局限性。 It doesn't recognize the not in self.variable_name defined variables like you have used above.它无法识别您在上面使用的 not in self.variable_name定义的变量。 It might help you n.netheless, because you can simply define them in init.尽管如此,它可能对您有所帮助,因为您可以简单地在 init 中定义它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM