Python 在循环中动态添加方法时,作用域已捕获
我有一个API来分析我的运动数据(我从scrape的网站上下载) 我的主类是pandas.DataFrame的一个子类,它基本上是一个表格数据的容器。它支持按列名索引,返回列值数组 我想根据数据中存在的“健身活动”类型添加一些便利属性。例如,我想添加一个属性“running”:Python 在循环中动态添加方法时,作用域已捕获,python,pandas,Python,Pandas,我有一个API来分析我的运动数据(我从scrape的网站上下载) 我的主类是pandas.DataFrame的一个子类,它基本上是一个表格数据的容器。它支持按列名索引,返回列值数组 我想根据数据中存在的“健身活动”类型添加一些便利属性。例如,我想添加一个属性“running”: @property def running(self): return self[self['type'] == 'running'] 它将返回数据帧中所有在“type”列中具有“running”的行 我尝试对
@property
def running(self):
return self[self['type'] == 'running']
它将返回数据帧中所有在“type”列中具有“running”的行
我尝试对数据中存在的所有类型动态执行此操作。下面是我天真地做的:
class Activities(pandas.DataFrame):
def __init__(self,data):
pandas.DataFrame.__init__(self,data)
# The set of unique types in the 'type' column:
types = set(self['type'])
for type in types:
method = property(lambda self: self[self['type'] == type])
setattr(self.__class__,type,method)
结果是,所有这些属性都返回了同一类型活动(“行走”)的数据表
发生的事情是,当访问属性时,会调用lambda,它们会在定义名称“type”的范围内查找。他们发现它绑定到字符串“walking”,因为这是for循环的最后一次迭代。for循环的每个迭代都没有自己的名称空间,因此所有lambda只看到最后一次迭代,而不是实际定义时“type”所具有的值
有人能想出一个办法来解决这个问题吗?我能想到两种,但它们似乎并不特别理想:
\uuuu getattr\uuuu
以检查属性是否为活动类型并返回相应的行这两个对我的口味来说都有点太聪明了,而且
pandas.DataFrame
已经有了一个\uu getattr\uuuu
,如果我也做了一个,我必须谨慎地与之交互。递归可以工作,但感觉非常错误,因为类型集没有任何内在的树状结构。它是平面的,在代码中应该是平面的 修改lambda
以将值拉入新范围
method = property(lambda self=self, type=type: self[self['type'] == type])
老实说,如果可以避免的话,我建议不要创建DataFrame的子类。根据我的经验,Java古老的格言“重组合轻继承”更可取 太好了,这正是我需要的!但是,如果这个对象有多个实例,lambda(self)的第一个参数可能不应该有默认设置。这是因为,正如我刚刚发现的,您必须向类中添加属性,而不是实例(在我的问题中编辑)。因此,我们不希望属性指向特定实例,否则对象将返回彼此的数据!我几乎总是同意你的看法,但在这种情况下,我想要的对象在各个方面都是一个
DataFrame
,唯一的区别是添加了这些方法。因此,如果我改用组合,我将真正地包装每个DataFrame
方法。我猜,当子类化时,您通常只需要父类功能的一个子集,在这种情况下,我真的需要全部功能。