Python 如何设置一个包含所有方法和函数的类,比如内置的float,但保留额外的数据?

Python 如何设置一个包含所有方法和函数的类,比如内置的float,但保留额外的数据?,python,class,inheritance,floating-point,data-extraction,Python,Class,Inheritance,Floating Point,Data Extraction,我正在处理大约100000个值的2个数据集。这两个数据集只是列表。列表中的每个项目都是一个小类 class Datum(object): def __init__(self, value, dtype, source, index1=None, index2=None): self.value = value self.dtype = dtype self.source = source self.index1 = inde

我正在处理大约100000个值的2个数据集。这两个数据集只是列表。列表中的每个项目都是一个小类

class Datum(object):
    def __init__(self, value, dtype, source, index1=None, index2=None):
        self.value = value
        self.dtype = dtype
        self.source = source
        self.index1 = index1
        self.index2 = index2
对于一个列表中的每个数据,另一个列表中有一个匹配的数据,该数据具有相同的数据类型、源、index1和index2,我使用它对两个数据集进行排序,使它们对齐。然后,我对匹配数据点的值执行各种工作,这些值总是浮动的

目前,如果我想确定一个数据集中浮点数的相对值,我会这样做

minimum = min([x.value for x in data])
for datum in data:
    datum.value -= minimum
minimum = min(data)
data = [x - minimum for x in data]
然而,让我的自定义类从float继承并能够像这样工作会很好

minimum = min([x.value for x in data])
for datum in data:
    datum.value -= minimum
minimum = min(data)
data = [x - minimum for x in data]
我尝试了以下方法

class Datum(float):                                                                                                                                                                                                                                        
    def __new__(cls, value, dtype, source, index1=None, index2=None):                                                        
        new = float.__new__(cls, value)                                                                            
        new.dtype = dtype                                                                                          
        new.source = source                                                                                        
        new.index1 = index1                                                                                                  
        new.index2 = index2
        return new
但是,

data = [x - minimum for x in data]
删除所有额外属性(dtype、source、index1、index2)

我应该如何设置一个类,该类的功能类似于一个float,但保留我实例化它时使用的额外数据


更新:除了减法之外,我还做很多类型的数学运算,因此重写所有使用浮点运算的方法都会非常麻烦,坦率地说,我不确定我是否能正确重写它们。

问题是当你这样做时:

x - minimum
就您正在执行的类型而言:

datum - float, or datum - integer
无论哪种方式,python都不知道如何执行这两种操作,所以如果可以的话,它所做的就是查看参数的父类。因为基准是一种浮点类型,所以它可以很容易地使用浮点-并且计算结果是

float - float 
这显然会导致“float”——除非您告诉它,否则python无法知道如何构造数据对象

要解决这个问题,您需要实现数学运算符,以便python知道如何执行
datum-float
,或者提出不同的设计

假设“dtype”、“source”、index1和index2在计算后需要保持不变,那么作为示例,您的类需要:

def __sub__(self, other):
      return datum(value-other, self.dtype, self.source, self.index1, self.index2)
这应该是有效的-不需要测试

这将允许你这样做

d = datum(23.0, dtype="float", source="me", index1=1)
e = d - 16
print e.value, e.dtype, e.source, e.index1, e.index2
这将导致:

7.0 float  me  1  None

我建议对float进行子类化,并使用一对修饰符“捕获”任何方法的float输出(当然,除了
\uuu new\uuu
),然后返回
数据对象,而不是
float
对象

首先,我们编写方法decorator(下面实际上没有将其用作decorator,它只是一个修改另一个函数(也称为包装函数)输出的函数):

第一个装饰器仅适用于它所附加的方法。但我们希望它装饰从
float
继承的所有(实际上,几乎所有)方法(不管怎样,那些出现在float的
\uuuu dict\uuuu
中的方法)。第二个修饰符将我们的第一个修饰符应用于float子类中的所有方法,除了列为exceptions()的方法外:

现在,我们编写的子类与您以前编写的子类基本相同,但是经过修饰,并且从修饰中排除
\uuuu new\uuuu
(我想我们也可以排除
\uuuu init\uuuu
,但是
\uuuu init\uuuuuu
不会返回任何内容):

以下是我们的测试程序;迭代似乎工作正常:

d1 = Datum(1.5)
d2 = Datum(3.2)
d3 = d1+d2
assert d3.source == 'source'
L=[d1,d2,d3]
d4=max(L)
assert d4.source == 'source'
L = [i for i in L]
assert L[0].source == 'source'
assert type(L[0]) == Datum
minimum = min(L)
assert [x - minimum for x in L][0].source == 'source'
注:

  • 我正在使用Python3。不确定这是否会对你产生影响
  • 这种方法有效地覆盖了除异常之外的所有float方法,即使是结果未被修改的方法。这可能会有副作用(对内置函数进行子类化,然后覆盖它的所有方法),例如性能问题或其他问题;我真的不知道
  • 这也将装饰嵌套类
  • 同样的方法也可以使用元类实现
您可能需要定义所有的数学方法,以便任何数学运算产生的结果都是一个基准,而不是一个浮点。假设在您进行计算时,dtype、source、index1和index2不会发生变化,那么我的答案应该是有效的。在您的案例中,额外的方法并不复杂。
d1 = Datum(1.5)
d2 = Datum(3.2)
d3 = d1+d2
assert d3.source == 'source'
L=[d1,d2,d3]
d4=max(L)
assert d4.source == 'source'
L = [i for i in L]
assert L[0].source == 'source'
assert type(L[0]) == Datum
minimum = min(L)
assert [x - minimum for x in L][0].source == 'source'