前言
今天市场同学反馈了一个问题,网站的默认SEO信息不正确,显示了默认的SEO标题。一番排查,发现所有问题都指向了 hasattr
1 | from django.conf import settings |
上面的 hasattr(self, 'suggest_seo'):
居然是False
, 自己写了个Demo又是正确的。因此借助搜索引擎,找到了下面文章解决了我的疑惑:你用对 hasattr 了嘛?。
简而言之,就是说属性在计算的时候报错就会导致hasattr
为False
。 也就是说在 Python2,如果你想要判断一个类里面是否有某个 property,需要确认它会不会有机会抛错。如果它有可能会异常,那么应该用 getattr(让异常发生)。
下面摘录一下原文:
你用对 hasattr 了嘛?
前天帮一个同学 DEBUG 一个很奇怪的问题,发现了一个 Python 2 的 hasattr 一个不适用场景,和大家分享一下。
在日常开发中,判断对象有没有一个属性,你可能这么写:
1 | if hasattr(self, 'redirect_url'): |
如果 self 有 redirect_url 这个属性,那么请求直接重定向到 redirect_url 这个 URL 上。看起来没有问题对吧,我们写的更完整一些:
1 | In [1]: class VideoSubject(object): |
看到了吧 hassattr 的结果是 False,也就是说 Python 2 认为 vs 这个实例就没有 redirect_url 属性。但是看代码是有这个 propery 的,只是在计算时由于某些原因抛错误了。
我 debug 了好久才发现这个原来是这个问题,🤦
感觉网上搜了下,原来 attrs 的作者,Python 核心开发在 16 年就写过一篇文章介绍这个事情:
https://hynek.me/articles/hasattr/
也就是说在 Python2,如果你想要判断一个类里面是否有某个 property,需要确认它会不会有机会抛错
如果它有可能会异常,那么应该用 getattr(让异常发生):
1 | In [4]: getattr(vs, 'redirect_url', None) |
另外在 CPython 实现,hasattr 其实内部还是用了 getattr 的:
1 | /* 2.7/Python/bltinmodule.c#L828-L858 */ |
注意result = PyObject_GetAttr(v, name)
这步,所以 getattr 要比 hasattr 更快更直接。
而在 Python 3 没有这个问题,他会捕获 AttributeError 返回 False,而其他错误直接抛出来:
1 | /* |
也就抛出了 PyExc_AttributeError 会被清除(其他的错误照常 raise)
延伸阅读
- https://hynek.me/articles/hasattr/
- https://github.com/python/cpython/blob/3.7/Objects/object.c#L1231-L1242
本文链接: http://www.ionluo.cn/blog/posts/18af7293.html
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!