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

时间:2019-08-06 15:53:45

标签: python class attributes instance

我希望始终将类的实例视为其实例之一,除非特别要求其他属性。例如,假设我的课是:

class Value:

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

使得value是一个浮点数,而description是一个字符串。现在,除非特别要求Value,否则我想始终Instance.value的实例视为Instance.description

我知道两种解决方案。第一种是通过以下方式在类中实现数字仿真:

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

用于每种可能的数值运算。但是,这似乎过于繁琐-如果有人想使用Value实例来乘以一个列表,又会出现什么错误消息,以及在类实例而不是基本float上进行操作的所有其他方式会出错吗?我真的必须针对每种可能的操作案例引入类方法吗?

第二种解决方案是通过以下方式重新定义内容:

class Value(float):
    pass

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

现在,该实例只是浮点值,并且说明已进行了硬编码。但这似乎也很繁琐,而且具有非Pythonic的特性。

我是否为此错过了一种非常简单的方法?还是我可以滑动的某个布尔标志?对于Python来说,似乎常常需要一种方法。

1 个答案:

答案 0 :(得分:1)

“简单的解决方案”是您的第二个答案-子类,无论您尝试使用的值是什么。您仍然可以覆盖__init__并添加所需的任何实体(尽管您还必须覆盖__new__-请参见this answer):

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已经已经定义了所有算术运算符,而您只是继承了它。缺点是浮点数是不可变的,因此创建对象后就无法更改其值。

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