Python Block类方法报错及实例变量定义问题求助
问题解决:Block类中实例变量与默认参数的坑
问题背景
自定义Block类,需要实现一个接收外部pandas DataFrame的方法。初始代码运行报错'list' object is not callable,添加self.关键字后方法能正常执行,但发现self.relation被当作类变量(多个实例共享同一个列表),需要修正这个问题。
初始错误代码
df = {'subject': ['foo', 'bar'], 'object': ['bar', 'foo']} cond_df = pd.DataFrame(data=df) class Block: def __init__(self, name = 'no_name', dimension = [0,0,0,0,0,0,0], relation = [] ): self.name = name self.dimension = dimension self.relation = relation def get_relation(self, cond_df): for i in range(len(cond_df['subject'])): if cond_df['subject'][i] == name: relation.append([cond_df['object'][i], 0]) # 实体作为subject时,标记为父节点'0' elif cond_df['object'][i] == name: relation.append([cond_df['subject'][i], 1]) # 实体作为object时,标记为子节点'1' return(relation) a_block = Block() a_block.get_relation(cond_df)
修改后仍有问题的代码
class Block: def __init__(self, name = 'no_name', dimension = [0,0,0,0,0,0,0],relation = [] ): self.name = name self.dimension = dimension self.relation = relation def get_relation(self, cond_df): for i in range(len(cond_df['subject'])): if cond_df['subject'][i] == self.name: self.relation.append([cond_df['object'][i], 0]) # 实体作为subject时,标记为父节点'0' elif cond_df['object'][i] == self.name: self.relation.append([cond_df['subject'][i], 1]) # 实体作为object时,标记为子节点'1' return(self.relation) a_block = Block(name = 'foo') a_block.get_relation(cond_df)
错误原因分析
- 初始代码报错原因:
get_relation方法中直接使用name和relation,未通过self.引用实例变量,导致Python无法定位到实例属性(若全局存在同名列表变量,会误操作全局变量,进而引发'list' object is not callable错误)。 - self.relation变成类变量的原因:Python中,可变类型(如列表、字典)作为函数默认参数时,会在类定义阶段创建一次,所有实例共享同一个对象。因此
__init__里的relation = []是一个类级别的列表,所有Block实例的self.relation都会指向这个列表,造成“类变量”的假象。
修复方案
步骤1:修正__init__的默认参数
将可变类型的默认参数改为None,在__init__内部初始化实例变量,确保每个实例拥有独立的列表:
class Block: def __init__(self, name='no_name', dimension=None, relation=None ): self.name = name # 初始化dimension为默认列表 self.dimension = dimension if dimension is not None else [0,0,0,0,0,0,0] # 初始化relation为新的空列表,每个实例独立拥有 self.relation = relation if relation is not None else [] def get_relation(self, cond_df): for i in range(len(cond_df['subject'])): if cond_df['subject'][i] == self.name: self.relation.append([cond_df['object'][i], 0]) elif cond_df['object'][i] == self.name: self.relation.append([cond_df['subject'][i], 1]) return self.relation
步骤2:优化get_relation方法(可选,提升效率)
用pandas的向量化操作替代循环,处理大数据集时速度更快:
def get_relation(self, cond_df): # 筛选当前name作为subject的行,提取object并标记0 parent_rows = cond_df[cond_df['subject'] == self.name] self.relation.extend([[obj, 0] for obj in parent_rows['object']]) # 筛选当前name作为object的行,提取subject并标记1 child_rows = cond_df[cond_df['object'] == self.name] self.relation.extend([[subj, 1] for subj in child_rows['subject']]) return self.relation
验证效果
创建多个实例测试,每个实例的relation都是独立的:
df = {'subject': ['foo', 'bar', 'foo'], 'object': ['bar', 'foo', 'baz']} cond_df = pd.DataFrame(data=df) block1 = Block(name='foo') block1.get_relation(cond_df) print(block1.relation) # 输出:[['bar', 0], ['baz', 0], ['bar', 1]] block2 = Block(name='bar') block2.get_relation(cond_df) print(block2.relation) # 输出:[['foo', 0], ['foo', 1]]
内容的提问来源于stack exchange,提问作者Shmou
相关产品推荐
相关产品推荐

