问题描述
这是一个更好的办法来检查属性的存在?
Which is a better way to check for the existence of an attribute?
的提供了这样的回答:
Jarret Hardie provided this answer:
if hasattr(a, 'property'):
a.property
我看到,它也可以做这样的:
I see that it can also be done this way:
if 'property' in a.__dict__:
a.property
是一个方法通常比别人多采用?
Is one approach typically used more than others?
推荐答案
有没有最好的方式,,因为你永远只是检查,看看是否一个属性存在;它往往是一些较大项目的一部分。有几种正确的方式和一个显着的不正确的方法。
There is no "best" way, because you are never just checking to see if an attribute exists; it is always a part of some larger program. There are several correct ways and one notable incorrect way.
if 'property' in a.__dict__:
a.property
下面是一个演示,显示这种技术失败:
Here is a demonstration which shows this technique failing:
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
输出:
'prop' in a.__dict__ = False
hasattr(a, 'prop') = True
a.prop = 3
在大多数情况下,你不想与 __ __字典
一塌糊涂。这是做特别的东西,并检查是否一个属性存在相当平凡的一个特殊的属性。
Most of the time, you don't want to mess with __dict__
. It's a special attribute for doing special things, and checking to see if an attribute exists is fairly mundane.
在Python中常见的成语是更容易请求原谅比许可,或EAFP的简称。你会看到很多的Python code,它使用这个成语,而不是只检查是否存在属性。
A common idiom in Python is "easier to ask for forgiveness than permission", or EAFP for short. You will see lots of Python code that uses this idiom, and not just for checking attribute existence.
# 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()
请注意,这是完全打开,可能不存在的文件相同的成语。
Note that this is exactly the same idiom for opening a file that may not exist.
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
另外,对于字符串转换为整数。
Also, for converting strings to integers.
try:
i = int(s)
except ValueError:
print "Not an integer! Please try again."
sys.exit(1)
即使进口的可选模块...
Even importing optional modules...
try:
import readline
except ImportError:
pass
的LBYL方式
的 hasattr
方法,当然也可以。这种技术被称为短期或LBYL三思而后行。
The LBYL way
The hasattr
method, of course, works too. This technique is called "look before you leap", or LBYL for short.
# Cached attribute
if not hasattr(self, 'big_object'):
big_object = CreateBigObject()
self.big_object = CreateBigObject()
big_object.do_something()
(即 hasattr
内置居然出奇3.2之前的行为在Python版本方面的例外 - 它会捕获异常,它不应该 - 但是这可能是无关紧要的,因为这样的例外是不可能的。在 hasattr
技术也比慢尝试/除
,但你不知道把它往往不够关心,差异不是很大。最后, hasattr
不是原子,因此它可能抛出 AttributeError的
如果另一个线程删除属性,但是这是一个牵强的场景,你需要围绕主题非常小心,无论如何,我不认为任何这三个差异是值得担忧的。)
(The hasattr
builtin actually behaves strangely in Python versions prior to 3.2 with regard to exceptions -- it will catch exceptions that it shouldn't -- but this is probably irrelevant, since such exceptions are unlikely. The hasattr
technique is also slower than try/except
, but you don't call it often enough to care and the difference isn't very big. Finally, hasattr
isn't atomic so it could throw AttributeError
if another thread deletes the attribute, but this is a far-fetched scenario and you'll need to be very careful around threads anyway. I don't consider any of these three differences to be worth worrying about.)
使用 hasattr
比简单得多尝试/除
,只要所有你需要知道的是,是否属性存在。对我来说最大的问题是,LBYL技术看起来奇怪,因为作为一个Python程序员,我更习惯阅读EAFP技术。如果你把上面的例子,让他们使用 LBYL
的风格,你就会得到code要么是笨拙的,完全不正确,或太难写了。
Using hasattr
is much simpler than try/except
, as long as all you need to know is whether the attribute exists. The big issue for me is that the LBYL technique looks "strange", since as a Python programmer I'm more used to reading the EAFP technique. If you rewrite the above examples so that they use the LBYL
style, you get code that is either clumsy, outright incorrect, or too difficult to write.
# 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有时是彻头彻尾的不正确的:
And LBYL is sometimes outright incorrect:
if os.path.isfile('some_file'):
# At this point, some other program could
# delete some_file...
f = open('some_file', 'r')
如果你想编写一个函数LBYL导入可选模块,是我的客人......这听起来像功能将是一个总的怪物。
If you want to write a LBYL function for importing optional modules, be my guest... it sounds like the function would be a total monster.
如果你只需要一个默认值, GETATTR
是的一个较短的版本尝试/除
。
If you just need a default value, getattr
is a shorter version of try/except
.
x = getattr(self, 'x', default_value)
如果默认值是昂贵的构造,那么你会像这样结束:
If the default value is expensive to construct, then you'll end up with something like this:
x = getattr(self, 'attr', None)
if x is None:
x = CreateDefaultValue()
self.attr = x
或者,如果无
是一个可能的值,
sentinel = object()
x = getattr(self, 'attr', sentinel)
if x is sentinel:
x = CreateDefaultValue()
self.attr = x
结论
在内部, GETATTR
和 hasattr
建宏只是使用尝试/除
技术(除了用C语言编写)。因此,他们的行为都重要的地方以同样的方式,并选择合适的一个是由于环境和风格问题。
Conclusion
Internally, the getattr
and hasattr
builtins just use try/except
technique (except written in C). So they all behave the same way where it counts, and picking the right one is due to a matter of circumstances and style.
的尝试/除
EAFP code总是会擦一些程序员走错了路,而 hasattr / GETATTR
LBYL code会激怒其他程序员。他们都是正确的,而且往往没有真正令人信服的理由选择一个或其他。 (然而,其他程序员很反感,你会认为这是很正常的一个属性是不确定的,有的程序员都吓坏了,它甚至有可能有在Python一个未定义的属性)。
The try/except
EAFP code will always rub some programmers the wrong way, and the hasattr/getattr
LBYL code will irk other programmers. They're both correct, and there's often no truly compelling reason to pick one or the other. (Yet other programmers are disgusted that you would consider it normal for an attribute to be undefined, and some programmers are horrified that it's even possible to have an undefined attribute in Python.)
这篇关于这是检查属性是否存在的最佳方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!