【问题标题】:Creation and persistence of a class property in PythonPython中类属性的创建和持久化
【发布时间】:2016-01-25 23:52:17
【问题描述】:

我正在编写一个简单的类来检索以恒定采样率 Fs 数字化的信号 x。数字化从时间t0 开始。给定信号长度N = len(x)、采样率和初始时间,信号的时基是唯一确定的。我很少需要访问时基,但我想在需要时使用一种简单的方法。下面,我使用property() 装饰器实现了我想要的时基功能的最小工作示例:

import numpy as np


class Signal(object):
    def __init__(self, x, Fs, t0):
        self.x = x
        self.Fs = Fs
        self.t0 = t0
        return

    @property
    def t(self):
        return self.t0 + (np.arange(len(self.x)) / self.Fs)

我想了解时基属性Signal.t 的创建和“持久性”。以下面的示例用例为例:

    x = np.arange(10)
    Fs = 1.
    t0 = 0.

    sig = Signal(x, Fs, t0)
    print sig.t

时基数组t是什么时候生成的?在初始化期间还是在调用print sig.t 时动态调用?如果sig.t 属性是动态计算的,它会在print 命令之外持续吗? (即是否已分配内存以将时基存储为对象属性?)。

虽然上面是一个简单的例子,但我的典型信号非常大,我确实想要为每个信号创建和存储时基的内存开销。但是,我想要一种根据需要动态生成时间基准的简单方法;时基在一次性使用后不应作为对象属性持续存在(例如,用于创建原始信号图)。

如果 property() 装饰器没有提供这种所需的功能(即最小的内存开销,在需要的基础上易于使用),我应该使用什么?只是一个类方法?还是有不同的、更优化的解决方案?谢谢!

【问题讨论】:

    标签: python python-2.7 class memory properties


    【解决方案1】:

    每次访问sig.t,你用@property修饰的t函数就(重新)运行,结果作为sig.t的值。这意味着数组是按需创建的,永远不会存储在 t 对象上。

    您似乎想要这个,但我会对此保持警惕。通常预计物业访问会很便宜,而该物业并非如此。考虑改用普通方法。

    【讨论】:

    • "考虑改用普通方法。"那么只需删除 @property 装饰器呢?
    • @E.Davis:当然,使用sig.t() 而不是sig.t 访问它。
    【解决方案2】:

    时基数组t是什么时候生成的?

    使用时。即当你写print sig.t

    如果 sig.t 属性是动态计算的,它会在打印命令之外持续存在吗? (即是否已分配内存以将时基存储为对象属性?)。

    不。下次您的代码引用sig.t 时,将创建一个新对象。

    如果 property() 装饰器没有提供这种所需的功能(即最小的内存开销,在需要的基础上易于使用),我应该使用什么?只是一个类方法?还是有不同的、更优化的解决方案?谢谢!

    我怀疑这里有不同的意见...您可以修改代码,以便缓存值并在每次调用时返回相同的内容:

    class Signal(object):
        def __init__(self, x, Fs, t0):
            self.x = x
            self.Fs = Fs
            self.t0 = t0
            self._t = None
            return
    
        @property
        def t(self):
            if self._t is not None:
                return self._t
            self._t = self.t0 + (np.arange(len(self.x)) / self.Fs) 
            return self._t
    

    但是在这里你无法告诉班级应该重新计算t,除非你做一个setter...

    如果t 在初始化后不会改变,那为什么不把它设为公共属性呢?

    class Signal(object):
        def __init__(self, x, Fs, t0):
            self.x = x
            self.Fs = Fs
            self.t0 = t0
            self.t = self.t0 + (np.arange(len(self.x)) / self.Fs)
    

    【讨论】:

    • 关于将时基设为公共属性:为了减少内存消耗,我通常想要创建和存储时基。我只想要一个工具来轻松地为罕见的一次性使用创建时间基准。
    • @E.Davis -- 那么我建议使用常规方法。
    【解决方案3】:

    在您的示例中,您每次访问属性 t 时都会动态生成 Signal.t 值,因为您实际上是在调用 Signal.t() 来访问它。因此,您不会存储只是返回它的值.

    每当在类周围使用 @property 装饰器时,该函数充当“私有”(不是真正)变量的“getter”是很常见的,有时该“私有”变量有一个“setter”。

    当我指的是“私有”时,我真正指的是被命名以反映不应直接访问这些属性的属性。但是,在 python 中,您可以访问任何属性,因此没有任何私有变量,因为 python 对象可以很容易地更改。

    如果你想存储你的值,那么你应该这样做。

        import numpy as np
    
    
        class Signal(object):
            def __init__(self, x, Fs, t0):
                self.x = x
                self.Fs = Fs
                self.t0 = t0
                self._t = None
                return
    
            @property
            def t(self):
                if self._t is None:
                    self._t = self.t0 + (np.arange(len(self.x)) / self.Fs)
                return self._t
    
            @t.setter
            def t(self,value):
                self._t = value
    

    上面的例子,只会计算一次并将其存储在 _t 中,但你明白了。在使用 @property 装饰器时,通常会有一个底层变量用于检索和存储值。希望有所帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      • 1970-01-01
      • 2011-04-21
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 2013-04-06
      相关资源
      最近更新 更多