2008-10-15 60 views
23

我经常想检查一个对象是否有成员。一个例子是在函数中创建一个单例。为了这个目的,你可以使用hasattr这样的:在Python中检查成员存在

class Foo(object): 
    @classmethod 
    def singleton(self): 
     if not hasattr(self, 'instance'): 
      self.instance = Foo() 
     return self.instance 

但是你也可以这样做:

class Foo(object): 
    @classmethod 
    def singleton(self): 
     try: 
      return self.instance 
     except AttributeError: 
      self.instance = Foo() 
      return self.instance 

是另外的一种方法更好呢?

编辑:添加了@classmethod ...但是请注意,这个问题是不是如何做一个单身,但如何检查对象中的一员的存在。

编辑:对于例如,典型的用法是:

s = Foo.singleton() 

然后sFoo类型的对象中,相同的各一次。而且,通常这种方法会被多次调用。

+0

您能否举一个您正在尝试拨打的电话的例子以及该电话的预期回报? – Baltimark 2008-10-15 11:45:11

回答

21

这是两个不同的方法:№1是LBYL(三思而后行)和№2是EAFP(更容易请求宽恕而不是许可)。

Pythonistas通常认为EAFP较好,在“假设一个进程创建您测试它的时候,你试着自己创建它的时间之间的文件吗?”类型的参数。这种说法在这里并不适用,但它的总体思路。例外不应被视为例外。

性能明智的,你的情况 - 由于设置例外经理(该try关键字)是CPython的很便宜,同时创造为异常(raise关键字和内部异常创建)是什么,是相对expensive-使用方法№2的异常只会引发一次;之后,您只需使用该属性。

5

这取决于哪种情况是“典型的”,因为例外应该模拟非常非典型的情况。因此,如果典型情况是instance属性应该存在,则使用第二种代码样式。如果没有instanceinstance一样典型,则使用第一种样式。

在创建单例的具体情况中,我倾向于使用第一种样式,因为创建单例的初始时间是典型的用例。 :-)

10

我只是试图测量时间:

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 

在我的机器:

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 

看来,尝试/除了速度更快。这对我来说似乎也更易读,无论如何取决于案例,这个测试非常简单,也许你需要更复杂的测试。

+0

我不知道这些速度结果是否有些误导(但仍然非常有趣!),因为hasattr在后台使用异常来确定attr是否存在 – seans 2013-02-14 17:06:24

0

我不得不同意克里斯。请记住,在实际需要之前不要进行优化。我真的怀疑,检查存在是否会成为任何合理计划的瓶颈。

我没有看到http://code.activestate.com/recipes/52558/的方式来做到这一点,太。该代码的注释去掉,副本(“垃圾邮件”只是一个随机方法的类接口有):

class Singleton: 
    class __impl: 
     def spam(self): 
      return id(self) 
    __instance = None 
    def __init__(self): 
     if Singleton.__instance is None: 
      Singleton.__instance = Singleton.__impl() 
     self.__dict__['_Singleton__instance'] = Singleton.__instance 
    def __getattr__(self, attr): 
     return getattr(self.__instance, attr) 
    def __setattr__(self, attr, value): 
     return setattr(self.__instance, attr, value) 
+0

线自`.dict __ ['_ Singleton__instance'] = Singleton .__ instance`?这应该等同于self .__ instance = Singleton .__实例,不是吗? – PierreBdR 2008-10-15 13:58:48

1

使用它的方式有点偏离主题。单身人士高估了,而“共享状态”的方法是有效的,而且大多在蟒蛇很干净,例如:

class Borg: 
    __shared_state = {} 
    def __init__(self): 
     self.__dict__ = self.__shared_state 
    # and whatever else you want in your class -- that's all! 

现在每次你做:

obj = Borg() 

将有相同的信息,或者是相同的实例。