代码之家  ›  专栏  ›  技术社区  ›  PierreBdR

检查python中是否存在成员

  •  25
  • PierreBdR  · 技术社区  · 17 年前

    我经常想检查一个对象是否有成员。一个例子是在函数中创建一个单例。为此,您可以使用 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 每次都一样。通常,这个方法被多次调用。

    5 回复  |  直到 17 年前
        1
  •  21
  •   tzot    17 年前

    这是两种不同的方法:1是lbyl(跳跃前先看),2是eafp(请求宽恕比许可更容易)。

    pythonistas通常建议EAFP更好,其参数样式为“如果一个进程在您测试它的时间和您自己尝试创建它的时间之间创建了该怎么办?”.这个论点在这里不适用,但它是一般的想法。例外情况不应被视为 例外。

    在您的案例中,从绩效角度考虑,因为设立了异常管理者(以下简称“异常管理者”)。 try 关键字)在创建异常时在cpython中非常便宜 raise 关键字和内部异常创建)是相对昂贵的使用方法2,异常只会引发一次;然后,您只使用属性。

        2
  •  10
  •   Andrea Ambu    17 年前

    我只是试着测量时间:

    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
    

    似乎尝试/排除速度更快。它对我来说似乎也更易读,不管怎样,取决于具体情况,这个测试非常简单,也许你需要一个更复杂的测试。

        3
  •  5
  •   C. K. Young    17 年前

    这取决于哪一种情况是“典型的”,因为例外情况应该模拟不典型的情况。所以,如果典型的情况是 instance 属性应该存在,然后使用第二种代码样式。如果没有 实例 就像拥有 实例 ,然后使用第一种样式。

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

        4
  •  1
  •   gx.    17 年前

    在使用的过程中有点偏离主题。单例被高估了,“共享状态”方法在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()
    

    它将具有相同的信息,或者,在某种程度上是相同的实例。

        5
  •  0
  •   Brian    17 年前

    我必须同意克里斯的观点。记住,在你真正需要优化之前不要优化。我真的怀疑在任何合理的程序中,检查是否存在都会成为一个瓶颈。

    我确实看到了 http://code.activestate.com/recipes/52558/ 这也是一种方法。该代码的未注释副本(“spam”只是类接口的一个随机方法):

    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)