【问题标题】:Check if object attribute name appears in a string python检查对象属性名称是否出现在字符串python中
【发布时间】:2017-01-09 14:02:24
【问题描述】:

我想:

  • 检查字符串是否包含对象属性
  • 如果是,则访问该属性

所以对于类的对象

class Person(object):
    name = ""
    age = 0
    major = ""

    def __init__(self, name="", surname="", father="", age =0):
        self.name = name
        self.surname = surname
        self.father = father
        self.age = age
        self.identity = name +" "+ surname
    def __str__(self):
        return self.identity

    __repr__ = __str__

和对象

person = Person("Earl", "Martin", "Jason", 40)

我想要字符串“名字是什么” 返回人名 (我已经知道字符串是关于哪个对象的)

最基本的解决方案是为每个属性都做案例,但实际代码有很多,我相信我不必手动写出来,我只是编程新手,所以我不是确定使用什么语法

任何帮助表示赞赏

【问题讨论】:

  • 字符串“姓氏是什么”包含属性名称"name"。我假设您宁愿在这种情况下返回surname,但问题(如书面)是模棱两可的。另外,您想对明显包含多个属性名称的字符串做什么? (例如“名字和姓氏是什么?”)
  • @mgilson 感谢您的指出;是的,您的解释是正确的;至于第二个问题,我只能返回单个字符串,所以可能以先到者为准
  • @mgilson:贪婪是一个不错的解决方案;只需从恰好是对象属性的字符串中提取第一个完整的“单词”(例如,匹配正则表达式 r'\w+' 与偶数句柄下划线)。如果您从未将name 视为一个独立的词,您甚至不会检查它。比尝试执行 name in query 检查将匹配查询字符串中的部分单词更安全。

标签: python string python-2.7 class object


【解决方案1】:

您正在寻找函数hasattr()getattr()

检查属性是否存在:

hasattr(Person(), 'string')

并调用属性:

getattr(Person(), 'string')

【讨论】:

  • 仅供参考:有些人认为您应该几乎从不使用hasattr,而是更喜欢更冗长的if getattr(obj, string, sentinel) is sentinel 的变体。
  • @mgilson:我反对hasattr,但不赞成在成功案例中需要双​​重查找的不同LBYL 解决方案。 attr = getattr(obj, string, sentinel) 然后if attr is not sentinel: 很好,你只需要在if 检查之前存储结果。带有hasattr 的缺陷是它在成功的情况下将工作加倍(您仍然需要getattr,并且它与getattr 本身做同样的工作),因此使用EAFP patterngetattr 可以避免这种情况并发症。
  • @ShadowRanger -- 当然。我认为这实际上取决于您正在使用的对象。属性查找通常应该很快,所以在查找上加倍并不一定是坏事(除非你有一个对象,你知道属性查找可能很昂贵)。此外,在许多情况下,您只想知道某个属性是否存在,而不是对其值做任何事情(例如,这在__subclasshook__ 中被大量使用)。显然,EAFP 通常是首选 :-)。我最后的辩护是我确实说过“变体”:-P
  • @mgilson:我知道。我只是一个顽固的DRYer,我发现一个又一个使用hasattrgetattr 的模式令人讨厌(我同意重复查找的时间超过几微秒是不寻常的)。我也同意hasattr 在类型检查机制中占有合理的位置(当然,duck 打字通常更好,但我不是那里的纯粹主义者;如果鸭子打字不会爆炸,直到它处于混乱和很难恢复函数中的点,类型检查非常酷)。我接受你的辩护! :-)
【解决方案2】:

正如其他人所指出的,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

【讨论】:

  • 感谢您提供了一个很好解释的解决方案,还指出了我在不知不觉中遵循的 LBYL 模式的缺陷;在我的情况下,字符串中几乎肯定会出现一个属性,因此首选 EAFP 模式。
猜你喜欢
  • 2015-08-15
  • 2019-06-27
  • 1970-01-01
  • 1970-01-01
  • 2015-02-14
  • 2020-12-31
  • 2016-10-18
  • 1970-01-01
  • 2011-11-08
相关资源
最近更新 更多