Checking for member existence in Python
I regularly want to check if an object has a member or not. An example is the creation of a singleton in a function. For that purpose, you can use hasattr
like this:
class Foo(object):
@classmethod
def singleton(self):
if not hasattr(self, 'instance'):
self.instance = Foo()
return self.instance
But you can also do this:
class Foo(object):
@classmethod
def singleton(self):
try:
return self.instance
except AttributeError:
self.instance = Foo()
return self.instance
Is one method better of the other?
Edit: Added the @classmethod
... But note that the question is not about how to make a singleton but how to check the presence of a member in an object.
Edit: For that example, a typical usage would be:
s = Foo.singleton()
Then s
is an object of type Foo
, the same each time. And, typically, the method is called many times.
These are two different methodologies: №1 is LBYL (look before you leap) and №2 is EAFP (easier to ask forgiveness than permission).
Pythonistas typically suggest that EAFP is better, with arguments in style of "what if a process creates the file between the time you test for it and the time you try to create it yourself?". This argument does not apply here, but it's the general idea. Exceptions should not be treated as too exceptional.
Performance-wise in your case —since setting up exception managers (the try
keyword) is very cheap in CPython while creating an exception (the raise
keyword and internal exception creation) is what is relatively expensive— using method №2 the exception would be raised only once; afterwards, you just use the property.
I just tried to measure times:
class Foo(object):
@classmethod
def singleton(self):
if not hasattr(self, 'instance'):
self.instance = Foo()
return self.instance
class Bar(object):
@classmethod
def singleton(self):
try:
return self.instance
except AttributeError:
self.instance = Bar()
return self.instance
from time import time
n = 1000000
foo = [Foo() for i in xrange(0,n)]
bar = [Bar() for i in xrange(0,n)]
print "Objs created."
print
for times in xrange(1,4):
t = time()
for d in foo: d.singleton()
print "#%d Foo pass in %f" % (times, time()-t)
t = time()
for d in bar: d.singleton()
print "#%d Bar pass in %f" % (times, time()-t)
print
On my machine:
Objs created.
#1 Foo pass in 1.719000
#1 Bar pass in 1.140000
#2 Foo pass in 1.750000
#2 Bar pass in 1.187000
#3 Foo pass in 1.797000
#3 Bar pass in 1.203000
It seems that try/except is faster. It seems also more readable to me, anyway depends on the case, this test was very simple maybe you'd need a more complex one.
It depends on which case is "typical", because exceptions should model, well, atypical conditions. So, if the typical case is that the instance
attribute should exist, then use the second code style. If not having instance
is as typical as having instance
, then use the first style.
In the specific case of creating a singleton, I'm inclined to go with the first style, because creating a singleton the initial time is a typical use case. :-)
链接地址: http://www.djcxy.com/p/4920.html上一篇: 如何检查PHP数组是关联还是顺序?
下一篇: 在Python中检查成员存在