【问题标题】:Checking for member existence in Python在 Python 中检查成员是否存在
【发布时间】:2010-09-17 06:52:59
【问题描述】:

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

【问题讨论】:

  • 您能否举例说明您尝试拨打的电话以及该电话的预期回报?

标签: python exception introspection hasattr


【解决方案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()

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

【讨论】:

    【解决方案2】:

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

    我也确实将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)
    

    【讨论】:

    • 那么self.__dict__['_Singleton__instance'] = Singleton.__instance 的意义何在?这应该等价于 self.__instance = Singleton.__instance,不是吗?
    【解决方案3】:

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

    Pythonistas 通常建议 EAFP 更好,其参数风格为“如果一个进程在您测试它的时间和您尝试自己创建它的时间之间创建文件怎么办?”。这个论点在这里并不适用,但它是一般的想法。异常不应被视为异常。

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

    【讨论】:

      【解决方案4】:

      我只是尝试测量时间:

      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 更快。它对我来说似乎也更具可读性,无论如何取决于情况,这个测试很简单,也许你需要一个更复杂的。

      【讨论】:

      • 我想知道这些速度结果是否有点误导(但仍然很有趣!)因为 hasattr 在后台使用异常来确定 attr 是否存在
      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多