检查Python中的成员是否存在

Pie*_*BdR 26 python exception introspection hasattr

我经常想检查对象是否有成员.一个例子是在函数中创建单例.为此,您可以这样使用hasattr:

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

但你也可以这样做:

class Foo(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Foo()
            return self.instance
Run Code Online (Sandbox Code Playgroud)

另一种方法更好吗?

编辑:添加了@classmethod...但请注意,问题不是关于如何制作单例,而是如何检查对象中是否存在成员.

编辑:对于该示例,典型用法是:

s = Foo.singleton()
Run Code Online (Sandbox Code Playgroud)

然后s是类型的对象,Foo每次都相同.并且,通常,该方法被多次调用.

tzo*_*zot 22

这是两种不同的方法:№1是LBYL(在你跳跃之前看),№2是EAFP(比允许更容易请求宽恕).

Pythonistas通常建议EAFP更好,参数风格为"如果一个进程在你测试它的时间和你自己创建它的时间之间创建文件会怎么样?".这个论点不适用于此,但这是一般的想法.例外不应被视为特殊.

在你的情况下性能方面 - 因为设置异常管理器(try关键字)在CPython中非常便宜,而创建异常(raise关键字和内部异常创建)是相对昂贵的 - 使用方法№2异常将只引发一次; 之后,您只需使用该属性.


And*_*mbu 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
Run Code Online (Sandbox Code Playgroud)

在我的机器上:

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
Run Code Online (Sandbox Code Playgroud)

似乎try/except更快.它似乎对我来说更具可读性,无论如何取决于具体情况,这个测试很简单,也许你需要一个更复杂的测试.


Chr*_*ung 5

这取决于哪种情况是"典型的",因为例外情况应该是模型,嗯,非典型条件.因此,如果典型情况是该instance属性应该存在,那么使用第二种代码样式.如果没有instance那么典型instance,那么使用第一种风格.

在创建单例的特定情况下,我倾向于使用第一种样式,因为在初始时间创建单例是一个典型的用例.:-)