首页 > 解决方案 > 如何在 Python 中实现作用于实例属性的索引器/访问器

问题描述

基本目标:我有一个作为.data属性存储在类中的数据结构。这个类也可以有自己的属性和方法。我知道这里有一个类似的设计模式,例如,pandas DataFrame 依赖于 numpy narray in .values。我特别希望在 中包含一个 xarray 对象.data,但它同样可以是一个 pandas DataFrame(甚至是一个列表!)用于这个讨论。我想在我的类上有一个.loc(),或任何方法.iloc().isel()然后将该索引应用于.data属性。它不能直接修改.data属性(在原始实例中),因为它应该保持不变(否则您必须继续重新读取原始数据以重置您的实例.data,这将是愚蠢的)。我认为拥有受保护._data的财产将是大熊猫等似乎使用的技巧,但在这里看不到它的优势。看来我无论如何都必须制作(浅)副本,如:

    class Mydata():
        def __init__(self, attr, data):
            self.attr = attr
            self.data = data
            
        def coolmethod(self):
            print("Hello world")
            
        def isel(self, index):
            from copy import copy
            out = copy(self)
            out.data = out.data[index]
            return out

isel()所以现在我可以在我的类上调用一个方法,它在.data不丢失数据的情况下对属性进行子集化,因此:

mydata = Mydata('a string', [0, 1, 2, 3])
mydata.data
[0, 1, 2, 3]

mydata.attr
'a string'

mydata.coolmethod()
Hello world

mydata.isel(2).data
2

mydata.isel(3).data
3

mydata.isel(3).attr
'a string'

mydata.isel(3).coolmethod()
Hello world

mydata.data
[0, 1, 2, 3]

上面的例子说明了我想要的行为。我可以在我的实例上调用一个索引器,它返回一个.data修改后的新实​​例(由索引器),但其他属性仍然存在,因此允许使用不同的索引一次又一次地调用该方法。

关键似乎是制作(浅)副本。但是,这是最好的设计模式吗?我注意到,例如,pandas 确实使用属性 for.values.iloc,并.iloc返回 an_iLocIndexer但随后我对源代码的阅读变得冷淡。这对我的用例来说太花哨了吗?定义我自己的等价物_iLocIndexer(无论它是什么)会不会过大?.data通过使用而不是创建从 xarray 或 pandas 等子类化的类,我是否让自己走上了一条艰难的道路?

显然,我的 real.data会更有趣(即一个 xarray 数据集),我希望能够用它的iselseletc 索引器做同样的事情。

标签: pythonclassproperties

解决方案


推荐阅读