正如其他人所指出的,getattr 通常很有用。
hasattr 的用处较小;在内部,它基本上是try/except AttributeError: 块中的getattr 调用(如果出现AttributeError,它会返回False,没有异常意味着True),所以如果你正在考虑这样的代码:
if hasattr(myobj, attrname):
attr = getattr(myobj, attrname)
...
只需使用:
try:
attr = getattr(myobj, attrname)
except AttributeError:
pass
else:
...
避免将 LEGB 查找、函数调用和属性查找的次数加倍。
另外,对于重复拉取命名属性,operator.attrgetter 基本上可以让您制作 getattr 的优化版本,将属性名称预先绑定到查找(使其非常适合与 map 之类的东西一起使用和 filter 函数,因为它使它们比等效的 listcomps/genexprs 更有效)。
除此之外,根据您的目标,the dir 和(由于类that use __slots__ to define a known set of variables to reduce memory usage and prevent auto-vivification 的问题,可靠性稍差)vars functions 可能有用。
例如,在您从字符串中提取与单词对应的任何属性的示例中,您可以使用vars()/dir() 和您选择的filter 或@987654347 对合法属性名称进行批量识别@ 操作(或混合)取决于顺序、唯一性等的重要性:
from future_builtins import filter # Only on Py2, not Py3
import operator
import re
def query_obj(obj, querystr):
# Extract list of legal attribute names from string
words = re.findall(r'\w+', querystr)
# Reduce to names present on object's __dict__; no need to construct temporaries
attrnames = filter(vars(obj).__contains__, words)
# Alternate if __slots__ might be an issue (temp list & frozenset):
attrnames = filter(frozenset(dir(obj)).__contains__, words)
# Or combine the two to be sure (on Py3, use .keys() instead of .viewkeys())
# (temp list and set):
attrnames = filter((vars(obj).viewkeys() | dir(obj)).__contains__, words)
# Convenient way to get all names discovered at once; returns single object
# for single attr, tuple of objects for multiple attrs:
return operator.attrgetter(*attrnames)(obj)
# If you want a tuple unconditionally, use this instead:
return tuple(getattr(obj, name) for name in attrnames)
# Or to only return the first attribute encountered, raising StopIteration
# if no attributes are found:
return next(getattr(obj, name) for name in attrnames)
那么用法是:
>>> person = Person("Earl", "Martin", "Jason", 40)
>>> query_obj(person, "What is the name?")
'Earl' # Would be ('Earl',) in unconditional tuple case
>>> query_obj(person, "What is the name and surname?")
('Earl', 'Martin') # Would be 'Earl' in single return case