Python使用getattr调用方法时Case1返回None的原因及类Case1写法实现
原因说明
getattr是Python内置的属性查找函数,它的第二个参数仅接受纯属性名字符串,不会自动解析字符串中包含的括号、传参等调用语法,只会把传入的整个字符串做完全匹配,查找对象上的同名属性。
你写的Case1中传入的属性名是"find('span',{'class':'txt'})",代码会直接在i[0]对象上查找名字完全等于这个长字符串的属性,根本不会触发find方法的调用逻辑。而BeautifulSoup的标签对象重写了属性查找规则,访问不存在的普通属性时不会抛出AttributeError,而是默认返回None,这就是你拿到None返回值的根本原因。
Case2能正常运行,是因为传给getattr的第二个参数是纯属性名'find',正确拿到了对象绑定的find方法对象,之后再手动传入参数执行调用,所以能得到预期的标签结果。
类Case1形式的实现方案
如果要实现「动态指定方法+参数完成调用」的效果,可以选择以下几种可行方案:
- 标准getattr写法(最推荐,可读性、安全性最好)
拆分属性获取和调用两个步骤,是getattr的标准使用方式:# 先获取绑定的方法对象 find_func = getattr(i[0], "find") # 再传入参数执行调用 test = find_func('span', {'class': 'txt'}) - methodcaller封装写法
借助标准库operator的methodcaller,可以提前把方法名、固定参数封装成可调用对象,需要执行时直接传入目标实例即可:from operator import methodcaller # 提前封装方法名和入参 find_caller = methodcaller("find", 'span', {'class': 'txt'}) # 传入实例直接拿到调用结果 test = find_caller(i[0]) - eval动态执行写法(不推荐,存在安全风险)
如果一定要把完整调用逻辑写在单个字符串里,可以用eval执行拼接好的表达式,但绝对不能在处理用户可控输入的场景使用,会存在严重的代码注入漏洞:# 构造完整的执行表达式 expr = """i[0].find('span', {'class': 'txt'})""" test = eval(expr)
注意:生产环境优先选择前两种方案,非必要不要使用eval。
内容的提问来源于stack exchange,提问作者KimGyeongMin-KR
相关产品推荐
相关产品推荐

