循环遍历属性列表

3
我遇到了以下问题。我在我的类中有一个查看属性,它访问配置文件并且如果用户向配置文件添加垃圾信息则会引发ValueError异常。
我想编写一个方法来检查我的配置文件是否存在错误,因此我想逐个查看列表中的每个属性并尝试访问其值。因此,我不需要为每个属性复制try-except代码块。
我尝试了下面的代码,当创建列表时调用属性, 因此抛出异常超出了我的try块。 是否有优雅的解决方案?
import random


def load_config():
    rand_number = random.randint(0, 9)
    if rand_number == 5:
        raise ValueError

    return rand_number


class foo:
    @property
    def bar1(self):
        return load_config()

    @property
    def bar2(self):
        return load_config()

    @property
    def bar3(self):
        return load_config()

    @property
    def bar4(self):
        return load_config()

    @property
    def bar5(self):
        return load_config()


    def check_properties(self):
        properties = [
            self.bar1, //Exceptions are thrown here
            self.bar2,
            self.bar3,
            self.bar4,
            self.bar5,
        ]

        for property in properties:
            try:
                num = property
            except ValueError:
                print("ValueError at " + property.__name__)

my_foo = foo()
my_foo.check_properties()

为了创建一个mve,我将属性体替换为调用一个函数,该函数会创建一个随机的ValueError

你可以存储名称并使用 getattr(self, property_name) - Vincent Savard
1
@karthikr:这很正常。我认为你没有正确阅读问题。 - Vincent Savard
1
num = getattr(self, "bar1") 等等...就可以解决问题。 - tdelaney
@tdelaney 是的,基本上就像VincentSavard说的那样,它可以工作,但是一个没有字符串字面量的解决方案会更好。 - JDurstberger
1
@Altoyyr:你可以通过这样做获取所有属性名 [property_name for property_name, obj in self.__class__.__dict__.items() if isinstance(obj, property)]。我会写一个答案。 - Vincent Savard
显示剩余3条评论
1个回答

1
您可以像这样定义check_properties
def check_properties(self):
        properties = [property_name for property_name, obj in self.__class__.__dict__.items() 
                          if isinstance(obj, property)]

        for property_name in properties:
            try:
                getattr(self, property_name)
            except ValueError:
                print("ValueError at " + property_name)

它将尝试评估getattr中的属性。
对于基类继承的属性,这种方法不起作用。如果您使用继承,可以改用像这样的辅助函数:
def get_property_names(cls, follow_inheritance=False):
    property_names = []

    for attr_name, attr in cls.__dict__.items():
        if isinstance(attr, property):
            property_names.append(attr_name)

    if follow_inheritance:
        for parent_class in cls.__mro__:
            if parent_class != cls:
                property_names.extend(get_property_names(parent_class, True))

    return property_names

然后将check_properties定义为:
def check_properties(self):
        properties = get_property_names(self.__class__, follow_inheritance=True)

        for property_name in properties:
            try:
                getattr(self, property_name)
            except ValueError:
                print("ValueError at " + property_name)

1
只是为了提醒其他人,这个解决方案存在风险,因为它假设所有属性都应该被调用。如果你有其他需要在检查过程中不执行计算的属性,请不要使用此方法。此外,它也不会检查类的父级,所以如果你使用类继承,就需要进行更新。 - tdelaney
@tdelaney:我认为人们知道风险,因为问题字面上是“如何评估对象中的所有属性?”。不过你提到继承的观点也是有道理的。 - Vincent Savard
这绝对是一个有道理的观点,在我的情况下运作良好,但在其他情况下可能非常危险。 - JDurstberger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接