我经常想检查对象是否有成员.一个例子是在函数中创建单例.为此,您可以这样使用hasattr
:
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()
然后s
是类型的对象,Foo
每次都相同.并且,通常,该方法被多次调用.
这是两种不同的方法:№1是LBYL(在你跳跃之前看),№2是EAFP(比允许更容易请求宽恕).
Pythonistas通常建议EAFP更好,参数风格为"如果一个进程在你测试它的时间和你自己创建它的时间之间创建文件会怎么样?".这个论点不适用于此,但这是一般的想法.例外不应被视为太特殊.
在你的情况下性能方面 - 因为设置异常管理器(try
关键字)在CPython中非常便宜,而创建异常(raise
关键字和内部异常创建)是相对昂贵的 - 使用方法№2异常将只引发一次; 之后,您只需使用该属性.
我只是想测量时间:
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
似乎try/except更快.它似乎对我来说更具可读性,无论如何取决于具体情况,这个测试很简单,也许你需要一个更复杂的测试.
这取决于哪种情况是"典型的",因为例外情况应该是模型,嗯,非典型条件.因此,如果典型情况是该instance
属性应该存在,那么使用第二种代码样式.如果没有instance
那么典型instance
,那么使用第一种风格.
在创建单例的特定情况下,我倾向于使用第一种样式,因为在初始时间创建单例是一个典型的用例.:-)