通用惰性属性获取器/设置器

时间:2019-03-24 22:35:28

标签: python lazy-loading

这个问题基于this question,关于python类的惰性属性。

我真的很喜欢那里给出的解决方案:

  

这是惰性属性装饰器的示例实现:

import functools

def lazyprop(fn):
    attr_name = '_lazy_' + fn.__name__

    @property
    @functools.wraps(fn)
    def _lazyprop(self):
        if not hasattr(self, attr_name):
            setattr(self, attr_name, fn(self))
        return getattr(self, attr_name)

    return _lazyprop


class Test(object):

    @lazyprop
    def a(self):
        print 'generating "a"'
        return range(5)
  

互动会话:

>>> t = Test()
>>> t.__dict__
{}
>>> t.a
generating "a"
[0, 1, 2, 3, 4]
>>> t.__dict__
{'_lazy_a': [0, 1, 2, 3, 4]}
>>> t.a
[0, 1, 2, 3, 4]

此解决方案允许您为任何属性创建@lazyprop。但是,必须为希望懒惰的每个属性编写一个方法。我需要一些可以用于属性的名称,这些属性我会提前知道(其中可能有很多)。

这些属性是从hdf5文件读取的DataFrame。每个文件包含许多不同的表,我不知道它们的名称。我有一个出色的函数get_all_table_names(filename),该函数返回文件中所有表的名称。目前,我遍历所有名称,然后一个接一个地读取它们。但是,有几十GB的数据,需要几分钟才能读取。

有没有一种方法只能在方法调用该表时才实际读取该表?这里给出的示例是完美的,除了我需要提前知道表的名称。

编辑

将数据从HDF5文件加载到Pandas DataFrame的代码如下所示。

df = read_to_pandas(directory_of_files, 'table_name', number_of_files_to_read)

1 个答案:

答案 0 :(得分:0)

这是一个通用模板,显示了如何动态生成具有动态惰性属性的类:

import functools
import types


def lazyprop(added_value):
    """ Slightly generalize lazy attribute property decorator.
        (i.e. a decorator-factory)
    """
    def prop(fn):
        attr_name = '_lazy_' + fn.__name__ + str(added_value)

        @property
        @functools.wraps(fn)
        def _lazyprop(self):
            if not hasattr(self, attr_name):
                setattr(self, attr_name, fn(self, added_value))
            return getattr(self, attr_name)

        return _lazyprop

    return prop


def make_class(class_name, attrs):

    # Generic methods and class __dict__.
    def __init__(self):
        print('creating instance of class', self.__class__.__name__)

    def getter(self, added_value):
        return 41 + added_value

    cls_dict = {
        '__init__': __init__,
        '__repr__': lambda self: 'class name: %s' % class_name,
    }

    # Create and added lazy attributes.
    for i, attr_name in enumerate(attrs):
        cls_dict[attr_name] = lazyprop(i)(getter)

    cls = types.new_class(class_name, (), {}, lambda ns: ns.update(cls_dict))
    cls.__module__ = __name__

    return cls


if __name__ == '__main__':

    Foobar = make_class('Foobar', ('attr1', 'attr2'))

    foobar = Foobar()    # -> creating instance of class Foobar
    print(foobar)        # -> class name: Foobar
    print(foobar.attr1)  # -> 41
    print(foobar.attr2)  # -> 42