Python 动态生成视图

Python 动态生成视图,python,pandas,functools,Python,Pandas,Functools,我有几个类都引用相同的数据帧,但数据帧中只有一部分与每个类相关。我还希望在不使用高级索引的情况下轻松访问相关行,因为由于索引中的数字if级别,它变得重复。因此,我编写了生成分部函数的代码,以便每个类都可以查看其切片 from functools import partial import pandas as pd import numpy as np import dateutil.relativedelta as rd import datetime as dt class baz(obje

我有几个类都引用相同的数据帧,但数据帧中只有一部分与每个类相关。我还希望在不使用高级索引的情况下轻松访问相关行,因为由于索引中的数字if级别,它变得重复。因此,我编写了生成分部函数的代码,以便每个类都可以查看其切片

from functools import partial
import pandas as pd
import numpy as np
import dateutil.relativedelta as rd
import datetime as dt

class baz(object):
    pass

groups = ['foo', 'foo', 'bar', 'bar']
items = ['x','y', 'x', 'y']
diff = rd.relativedelta(years=1)

dates = [dt.date(2013,1,1) + (diff * shift) for shift in xrange(4)] * 2
index = pd.MultiIndex.from_arrays([groups, items], names=['groups', 'items'])
values = np.random.randn(4,8)

data = pd.DataFrame(values, index=index, columns=dates)

def view_data(group, item):
    return data.ix[group, item]

foo = baz()
bar = baz()

# I use partial because I want lazy evaluation
foo.x = partial(view_data, 'foo', 'x')
foo.y = partial(view_data, 'foo', 'y')
bar.x = partial(view_data, 'bar', 'x')
bar.y = partial(view_data, 'bar', 'y')

foo.x()
但是,我更希望引用不必看起来像foo.x()[date],而可以看起来像foo.x[date]

因此,我创建了一个decorator来包装函数并返回值

def execute_func(func):
    def inner(*args, **kwargs):
        return func(*args, **kwargs)
    return inner()

foo.x = execute_func(partial(view_data, 'foo', 'x'))
foo.y = execute_func(partial(view_data, 'foo', 'y'))
bar.x = execute_func(partial(view_data, 'bar', 'x'))
bar.y = execute_func(partial(view_data, 'bar', 'y'))
我担心的是,我不会总是获得数据帧的当前状态


这是实现我的目标的正确方法吗?

我个人建议您将数据帧包装在如下对象中:

class MyDataFrameView(object):

    def __init__(self, df):
        self.data = df

    def x(self):
        return self.data.ix['foo', 'x']

    def y(self):
        return self.data.ix['bar', 'y']
df = MyDataFrameView(data)
df.x()
你这样使用它:

class MyDataFrameView(object):

    def __init__(self, df):
        self.data = df

    def x(self):
        return self.data.ix['foo', 'x']

    def y(self):
        return self.data.ix['bar', 'y']
df = MyDataFrameView(data)
df.x()
如果更直观的话,您可以进一步添加方法作为属性

@property
def y(self):
    return self.data.ix['bar', 'y']
它本质上做的事情和你现在做的一样,但是它更简单,面向对象编程,而且——至少在我看来——更容易理解

您始终可以访问数据帧,如下所示:

df.data
或者,您可以直接在视图对象上实现更多方法,例如:

@property
def ix(self):
    return self.data.ix

def __getitem__(self, key):
    return self.data.__getitem__(key)
因此,对象的行为更像一个数据帧

请注意,这并不是真正的“动态”。如果您想要一种真正的动态方式,也可以使用getattr方法来实现

def __getattr__(self, attr):
   #code that "routes" to do the right thing given attr

这种模式通常称为组合,我最喜欢的实现“问题”的方法是使用
@property def x():…;将x作为属性添加到所有数据帧中。。。;pd.DataFrame.x=x
,直接子类化DataFrame也是一个选项。。。