为何getattr在属性存在时仍执行第三个参数?列表属性获取报错求助
问题分析与解决方案
这问题我之前也碰到过!核心原因是Python函数参数的求值顺序——不管函数会不会用到某个参数,所有参数都会在调用函数之前先计算出来。
为什么你的代码会报错?
当你写getattr(blocks[block_num], 'block_name', blocks[block_num][0].block_name)时,Python会先计算所有三个参数:
- 先算出
blocks[block_num] - 然后算出字符串
'block_name' - 最后强制算出
blocks[block_num][0].block_name
哪怕blocks[block_num]本身就有block_name属性(比如block_num=0时的Block实例),第三个参数的表达式还是会被执行。而Block类没有实现索引功能,所以blocks[0][0]直接抛出TypeError: 'Block' object does not support indexing。
解决单个元素的取值问题
你可以用两种方式避免这个问题:
方式1:先判断属性是否存在(请求许可)
先检查当前元素有没有目标属性,再决定取值逻辑:
block_num = 0 item = blocks[block_num] if hasattr(item, 'block_name'): name = item.block_name else: # 假设元素是列表,取第一个元素的block_name name = item[0].block_name
方式2:用try-except捕获异常(请求原谅)
这是更Pythonic的写法,先尝试直接取属性,失败了再处理列表的情况:
block_num = 0 item = blocks[block_num] try: name = item.block_name except AttributeError: # 没有block_name属性,尝试处理列表 name = item[0].block_name
实现最终目标:获取所有元素的名称
如果你的最终需求是把blocks列表(包括嵌套的内部列表)里所有Block实例的名称都取出来,可以写一个递归遍历的函数:
class Block(object): def __init__(self, name): self.block_name = name blocks_list = [Block("d"), Block("d"), Block("d")] blocks = [Block("a"), Block("b"), blocks_list, Block("c")] def get_all_block_names(items): names = [] for item in items: if hasattr(item, 'block_name'): names.append(item.block_name) elif isinstance(item, list): # 递归处理嵌套的列表 names.extend(get_all_block_names(item)) return names # 调用后得到所有名称 all_names = get_all_block_names(blocks) print(all_names) # 输出: ['a', 'b', 'd', 'd', 'd', 'c']
这个函数会自动处理嵌套的列表,不管嵌套多少层都能把所有Block的名称找出来。
内容的提问来源于stack exchange,提问作者Izik
相关产品推荐
相关产品推荐

