Pythonic 方法从 Python 对象获取两个属性之一

Pythonic way to get either one of two attributes from a Python object

我想从 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'")

class FruitBasket 只能装一种水果。没有同时存在苹果和橙子的风险。即使是这样,我仍然会在 n_fruits 中存储第一种水果(在这种情况下为苹果)。

我想要一个优雅的 Pythonic 方法来解决这个任务:我想到了很多可能的解决方案,但所有的解决方案都很丑陋且令人费解!

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

你的代码中断是因为你需要添加一个额外的 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)

我接受了@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_basket中所有属性和方法名称的列表。然后,我使用 intersection 方法仅获取 acceptable_fruits 中存在的属性。如果交集不为空,我提取第一个属性(在将集合转换为列表之后),否则我使用默认值。