检查Python中的成员是否存在

时间:2008-10-15 10:54:18

标签: python exception introspection hasattr

我经常想检查对象是否有成员。一个例子是在函数中创建单例。为此,您可以像这样使用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()

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

5 个答案:

答案 0 :(得分:22)

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

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

在您的情况下性能方面 - 因为设置异常管理器(try关键字)在CPython中非常便宜,同时创建异常(raise关键字和内部异常创建)是相对的昂贵 - 使用方法№2例外只会提出一次;之后,你只需使用该物业。

答案 1 :(得分: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

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

答案 2 :(得分:5)

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

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

答案 3 :(得分:1)

使用它的方式有点偏离主题。单身人士被高估了,而且“共享状态”方法在python中同样有效,而且大部分都非常干净,例如:

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()

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

答案 4 :(得分: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)