为所有操作模拟 class 实例的一个属性

Emulate one attribute of class instance for all operations

我希望我的 class 的实例始终被视为它的属性之一,除非特别请求其他属性。例如,假设我的 class 是:

class Value:

    def __init__(self, value, description):
        self.value = value
        self.description = description

这样 value 是一个浮点数,description 是一个字符串。现在,我希望 始终 的操作将 Value 的实例视为 Instance.value,除非明确要求 Instance.description

我知道有两种解决方案。第一种是通过以下方式在 class 中实现数值模拟:

def __add__(self, other):
    return self.value + other

每一个可能的数值运算。然而,这似乎过于麻烦——如果有人想使用一个 Value 实例来乘以一个列表怎么办,错误消息又如何,所有其他在 class 实例而不是基本 float 上操作的方法都可能出错?我真的必须为每个可能的操作案例引入 class 方法吗?

第二种解决方案是按以下方式重新定义事物:

class Value(float):
    pass

value1 = Value(8.0)
value1.description = 'The first value'
value2 = Value(16.3)
value2.description = 'The second value'
...
...

现在,实例只是浮点值,描述是硬编码的。但这看起来也很麻烦,而且令人难以置信地不 Pythonic。

我是否错过了一个非常简单的方法?或者我可以轻弹一下某个地方的某种布尔标志?似乎经常需要 Python 有办法。

"simple solution" 是您的第二个答案 - 子类化您尝试充当的任何值。您仍然可以覆盖 __init__ 并添加您需要的任何实体(尽管您还必须覆盖 __new__ - 请参阅 ):

class Value(float):
    def __new__(self, value, description=''):
        return float.__new__(self, value)
    def __init__(self, value, description=''):
        # let the superclass construct itself
        float.__init__(value)
        # give self a description
        self.description = description

value1 = Value(8.0, 'the first value')
value2 = Value(16.3, 'the second value')
print(value1 + value2)  # 24.3
print(value1 * value2)  # 130.4
print(value1.description)  # the first value
print(value2.description)  # the second value

这也与您的第一个可能的解决方案基本相同,除了 float 已经 已经 定义了所有算术运算符,而您只是继承了它。这里的缺点是浮点数是不可变的,因此在创建对象后不能更改值。

也可以创建一个装饰器来执行此操作,但这会复杂得多。