1

我想从 Python 对象中获取两个属性之一。如果这些属性都不存在,我想获得一个默认值。

例如,我想获取 FruitBasket 中苹果或橙子的数量,如果两者都不存在,我想将 n_fruits 设置为 0(因为我对其他水果不感兴趣)。

fruit_basket = FruitBasket(bananas=5)
try:
    n_fruits = getattr(fruit_basket, "apples")
except AttributeError as err:
    n_fruits = getattr(fruit_basket, "oranges")
except AttributeError as err:
    n_fruits = 0

如果既没有苹果也没有橙子,这段代码就会中断:

AttributeError("'FruitBasket' object has no attribute 'oranges'")

FruitBasket 类只能容纳一种水果。不存在同时存在苹果和橙子的风险。即使是这样,我仍然会将第一种水果(在本例中为苹果)存储在 n_fruits 中。

我想要一种优雅的 Pythonic 方式来解决这个任务:我想到了许多可能的解决方案,但它们都丑陋且令人费解!

顺便说一下,FruitBasket 只是一个例子。我实际上是在尝试从 scikit-learn 聚类器中获取质心。KMeans 和 MeanShift 算法将质心存储在“clusters_centers_”属性中,而 GaussianMixture 将其存储在“means_”属性中(出于我的目的,它们是相同的)。如果它们都不存在(在其他聚类算法的情况下),我想将质心设置为空列表。

4

2 回答 2

2

您的代码中断是因为您需要添加额外的 try-except 时出现异常:

fruit_basket = FruitBasket(bananas=5)
try:
    n_fruits = getattr(fruit_basket, "apples")
except AttributeError as err:
    try:
        n_fruits = getattr(fruit_basket, "oranges")
    except AttributeError as err:
        n_fruits = 0

更好的方法是只为 getattr 设置一个默认值:

fruit_basket = FruitBasket(bananas=5)
n_fruits = getattr(fruit_basket, "apples", None)
if n_fruits is None:
    n_fruits = getattr(fruit_basket, "oranges", 0)
于 2021-12-01T10:21:10.577 回答
1

我接受了@RoseGod 的答案,并在我的代码中使用它。尽管如此,我还是找到了另一种可能对某人有用的解决方案。

如果有两个以上可能的属性,我的解决方案可能更可取:在这种情况下,手动链接getattr可能容易出错。在这种情况下,我会做这样的事情:

fruit_basket = FruitBasket(bananas=5)
acceptable_fruits = ["apples", "oranges", "kiwis", "pineapples"]

fruits_in_basket = set(dir(fruit_basket)).intersection(acceptable_fruits)
fruits_in_basket = list(fruits_in_basket)
if fruits_in_basket:
    fruit_selected = fruits_in_basket[0]
    n_fruits = getattr(fruit_basket, fruit_selected)
else:
    fruit_selected = None
    n_fruits = 0

dir(fruit_basket)是一个包含所有属性和方法名称的列表fruit_basketacceptable_fruits然后,我只获取该方法中存在的属性intersection。如果交集不为空,我提取第一个属性(在将集合转换为列表之后),否则我使用默认值。

于 2021-12-01T13:32:10.827 回答