这个问题基于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)
这是一个通用模板,展示了如何使用动态延迟属性动态生成类:
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