【问题标题】:Pythonic way to get either one of two attributes from a Python object从 Python 对象中获取两个属性之一的 Pythonic 方法
【发布时间】:2022-01-07 22:17:58
【问题描述】:

我想从 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_”属性中(出于我的目的,它们是相同的)。如果它们都不存在(在其他聚类算法的情况下),我想将质心设置为一个空列表。

【问题讨论】:

    标签: python oop attributes python-object


    【解决方案1】:

    您的代码中断是因为您需要在出现异常时添加额外的 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)
    

    【讨论】:

    • 谢谢!我尝试了您的“更好的方法”,并且效果很好。它也非常易读,对我来说似乎是 Pythonic。
    • 欢迎您!因为它的 python 我确信有更多的方法可以解决这个问题,但是对我来说使用 getattr 的默认值看起来很简单(:
    【解决方案2】:

    我接受了@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 中存在的属性。如果交集不为空,则提取第一个属性(将集合转换为列表后),否则使用默认值。

    【讨论】:

    • 实际上,如果有两个以上的可能属性,此解决方案会更好。我只想指出这段代码中的一个错误是集合数据结构被称为唯一元素的无序集合,并且不支持索引或切片等操作。所以fruits_in_basket[0] 将导致 TypeError 你应该首先转换 fruits_in_basket到一个列表,而不是索引它。只需更改fruits_in_basket = list(set(dir(fruit_basket)).intersection(acceptable_fruits))
    • 你完全正确@RoseGod!感谢您指出代码中的错误!
    猜你喜欢
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-11
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多