【问题标题】:What is the proper pattern in Python for implementing lazy getters?Python 中实现惰性 getter 的正确模式是什么?
【发布时间】:2012-03-12 05:31:37
【问题描述】:

有时我喜欢为对象编写 getter 属性,这样在第一次调用它们时,繁重的工作就完成一次,然后保存该值并在以后的调用中返回。在objective-c中,我会使用一个ivar或一个静态变量来保存这个值。比如:

- (id)foo
{
    if ( _foo == nil )
    {
        _foo = // hard work to figure out foo
    }
    return _foo
}

这种相同的模式在 Python 中是否适用,或者是否有更可接受的方式来做到这一点?到目前为止,我的情况基本相同。我不喜欢我的解决方案的一点是,我的对象被值和这些值的 getter 弄乱了:

def foo(self):
    if not hasattr(self, "mFoo":
        self.mFoo = # heavy lifting to compute foo
    return self.mFoo

【问题讨论】:

    标签: python design-patterns getter


    【解决方案1】:

    请改用lazy property。吸气剂是so 1990's

    【讨论】:

      【解决方案2】:

      与其每次都进行显式的“hasattr”测试,不如让 Python 运行时为您完成这项工作。在您的类中定义__getattr__,仅在引用未定义的属性时调用。

      class Sth(object):
          @property
          def a(self):
              print "property a"
              return self._a
      
          def _a_compute(self):
              # put expensive computation code here
              print "_a_compute"
              return 1000
      
          def __getattr__(self, attr):
              print "__getattr__"
              if attr == '_a':
                  self._a = self._a_compute()
                  return self._a
      
      
      ss = Sth()
      print "first time"
      print ss.a
      print
      print "second time"
      print ss.a
      

      打印以下内容:

      first time
      property a
      __getattr__
      _a_compute
      1000
      
      second time
      property a
      1000
      

      您可以省略该属性并让__getattr__ 直接测试“a”,但是对于诸如内省或 IDE 自动完成之类的事情,您将无法看到“a”作为 dir 中的属性。

      【讨论】:

      • 谢谢,我起初对 getattrgetattribute 感到困惑。不过这是有道理的。
      【解决方案3】:

      我会这样做:

      @property
      def foo(self):
          return self._foo_value if hasattr(self, '_foo_value') else calculate_foo()
      
      def calculate_foo(self):
          self._foo_value = # heavy foo calculation
          return self._foo_value
      

      现在您可以访问“foo”,无论它是否已经计算过,使用:

      object.foo
      

      【讨论】:

        【解决方案4】:

        您可以在 Python 中使用完全相同的模式。您似乎担心是否必须一直做my_object.get_foo() 是Pythonic。值得庆幸的是,Python 以properties 的形式为您提供了一个很好的工具:

        class my_class(object):
        
             @property
             def foo(self):
               # calculate if needed
               return self._foo
        

        这可以让你拥有一些被使用作为属性的东西,即使它是作为一个函数实现的。即,用户会做my_object.foo,而不关心它在幕后运行的功能。

        另外需要注意的是,Python 约定说私有属性拼写为_foo 而不是mFoo

        【讨论】:

        • @darren 确实没有,这就是我在午夜发帖时得到的。 :) 我现在已经修好了。
        猜你喜欢
        • 2011-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-16
        • 2016-03-03
        • 1970-01-01
        • 2015-10-27
        • 2019-07-08
        相关资源
        最近更新 更多