当前位置: 首页 > 面试题库 >

哪个是检查属性是否存在的最佳方法?

李睿
2023-03-14
问题内容

哪种方法可以更好地检查属性是否存在?

Jarret Hardie提供了以下答案:

if hasattr(a, 'property'):
    a.property

我看到它也可以通过以下方式完成:

if 'property' in a.__dict__:
    a.property

一种方法通常比其他方法使用更多吗?


问题答案:

没有“最佳”方法, 因为您永远不会仅仅检查属性是否存在;它始终是某些较大程序的一部分。有几种正确的方法,一种值得注意的不正确的方法

if 'property' in a.__dict__:
    a.property

这是演示此技术失败的演示:

class A(object):
    @property
    def prop(self):
        return 3

a = A()
print "'prop' in a.__dict__ =", 'prop' in a.__dict__
print "hasattr(a, 'prop') =", hasattr(a, 'prop')
print "a.prop =", a.prop

输出:

a .__ dict__中的'prop'= False
hasattr(a,'prop')=真
a.prop = 3

大多数情况下,您不想惹恼__dict__。这是用于执行特殊操作的特殊属性,并且检查某个属性是否存在相当平凡。

EAFP方式

Python中一个常见的习惯用法是“比请求更容易获得宽恕”,或简称EAFP。您将看到很多使用此惯用语的Python代码,而不仅仅是检查属性是否存在。

# Cached attribute
try:
    big_object = self.big_object
    # or getattr(self, 'big_object')
except AttributeError:
    # Creating the Big Object takes five days
    # and three hundred pounds of over-ripe melons.
    big_object = CreateBigObject()
    self.big_object = big_object
big_object.do_something()

请注意,这与打开可能不存在的文件的用法完全相同。

try:
    f = open('some_file', 'r')
except IOError as ex:
    if ex.errno != errno.ENOENT:
        raise
    # it doesn't exist
else:
    # it does and it's open

同样,用于将字符串转换为整数。

try:
    i = int(s)
except ValueError:
    print "Not an integer! Please try again."
    sys.exit(1)

甚至导入可选模块…

try:
    import readline
except ImportError:
    pass

LBYL方式

hasattr方法当然也有效。这项技术称为“跳前先看”,简称LBYL。

# Cached attribute
if not hasattr(self, 'big_object'):
    big_object = CreateBigObject()
    self.big_object = CreateBigObject()
big_object.do_something()

hasattr在3.2之前的版本中,内建函数实际上在异常方面表现得很奇怪-它会捕获本不应该的异常-
但这可能是不相关的,因为此类异常的可能性很小。该hasattr技术也比慢try/except,但是您最后,hasattr它不是原子的,因此AttributeError如果另一个线程删除该属性可能会抛出该异常,但这是一个牵强的方案,您需要无论如何,我都非常谨慎地对待线程。我不认为这三个差异中的任何一个都值得担心。)

只要您需要知道的是属性是否存在,使用hasattr就会比容易得多try/except。对我来说,最大的问题是LBYL技术看起来“奇怪”,因为作为Python程序员,我更习惯于阅读EAFP技术。如果重写上面的示例以使它们使用LBYL样式,则您得到的代码要么笨拙,完全不正确,要么太难编写。

# Seems rather fragile...
if re.match('^(:?0|-?[1-9][0-9]*)$', s):
    i = int(s)
else:
    print "Not an integer! Please try again."
    sys.exit(1)

LBYL有时是完全不正确的:

if os.path.isfile('some_file'):
    # At this point, some other program could
    # delete some_file...
    f = open('some_file', 'r')

如果您想编写用于导入可选模块的LBYL函数,请成为我的客人……这听起来像是一个完全怪兽的函数。

getattr方式

如果您只需要默认值,请getattr使用的简短版本try/except

x = getattr(self, 'x', default_value)

如果默认值的构建成本很高,那么您将得到如下所示的结果:

x = getattr(self, 'attr', None)
if x is None:
    x = CreateDefaultValue()
    self.attr = x

或者如果None是可能的值,

sentinel = object()

x = getattr(self, 'attr', sentinel)
if x is sentinel:
    x = CreateDefaultValue()
    self.attr = x

结论

在内部,getattrhasattrbuildins仅使用try/except技术(用C编写的除外)。因此,它们的行为均以相同的方式进行,而选择正确的方法则取决于环境和风格。

try/exceptEAFP代码总是会擦一些程序员走错了路,和hasattr/getattrLBYL代码会激怒其他程序员。它们都是正确的,而且通常没有真正令人信服的理由选择其中一个。(但是,其他程序员对此感到恶心,因为您认为未定义属性是正常的,并且某些程序员感到震惊,甚至可能在Python中拥有未定义的属性。)



 类似资料:
  • 问题内容: 查看URL存在并且响应不是404的最佳方法是什么? 问题答案: 您可以使用 手册中的示例2 : 第一个数组元素将包含HTTP响应状态代码。您必须解析它。 请注意,示例中的函数将发出HTTP HEAD请求,这意味着它将不会获取URL的正文。这比使用GET请求(也将返回正文)更有效。 还要注意,通过设置 默认 上下文,任何使用http流上下文的后续调用现在都将发出HEAD请求。因此,确保完

  • 问题内容: 我有这样的示例列表: 现在,我检查它是否具有空字符串,如下所示: 这可以正常工作,因为它可以打印True,但是是否需要更多的pythonik方法? 问题答案: 您可以使用: 万一如果内部列表更大(超过100个项目),则与生成器一起使用的速度将比上面的示例更快,因为这样,使用Python for循环的速度代价将由快速操作来补偿: 时序比较:

  • 问题内容: 我有一个游标,带有来自选择的值,我想根据我是否发现任何行来做点什么。 这似乎不起作用,有帮助吗? 问题答案: 您需要在使用%FOUND属性之前对游标执行FETCH。将您的代码更改为类似 请注意,您可能需要将变量添加到FETCH语句的INTO子句中,在TABLE1和TABLE2中的每一列都需要添加一个变量。还要注意,编写此游标的方式可能会获得比预期更多的返回行。因为没有指定连接条件,所以

  • 问题内容: 可能是一个非常愚蠢的问题,检查elasticsearch中文档的字段是否存在的最佳方法是什么?我在文档中找不到任何内容。 例如,如果该文档没有字段/关键字“ price”,那么我不想返回结果。 {“ updated”:“ 2015/09/17 11:27:27”,“ name”:“ Eye Shadow”,“ format”:“ 1.5 g / 0.05 oz”,} 我可以做什么? 谢

  • 问题内容: 我正在尝试检查某一个是否为元音。这样做的最佳方法是什么? 问题答案: 这是我使用了一段时间的解决方案,但它并没有让我失望: 对于我的应用程序,它相当快。

  • 问题内容: 我想使用MySQL 5.x从表X中 高效地 选择所有表,其中表Y中 没有 满足某些条件的 相关行 ,例如 给我所有X记录,其中不存在与foo = bar相关的Y 据我了解,保证左外部联接可以为左(第一个)表中的每一行产生一行(在这种情况下为X),无论是否在联接表中找到满意的行。然后,我只想选择未找到任何行的那些行。 在我看来,如果没有匹配的记录,则y.X_id应该为NULL,但是此测试