【问题标题】:Python @property (setter method) that is restricted to setting data only in the __init__ methodPython @property(setter 方法),仅限于在 __init__ 方法中设置数据
【发布时间】:2014-09-15 12:51:28
【问题描述】:

我想设置一个在对象初始化阶段(即在 __init__() 方法期间)导入一些 raw_data 的对象。但是,我想让它从那时起只读。我正在考虑使用具有以下逻辑的 setter 属性 self.raw_data

@raw_data.setter
def raw_data(self, dataframe):
    <IF calling from __init__>?
        self.__raw_data = df

有没有办法让setter方法知道它是否从__init__中被调用? 阻止所有其他更改数据的尝试。

【问题讨论】:

  • 试试this recipe
  • 为什么不直接设置self.__raw_data
  • 我希望能够在 __init__() 方法中设置它,但没有其他地方可以有效地将变量 .__raw_data 转换为只读属性。我想保证它的状态,所以我以后不会无意中分配给 __raw_data。
  • 我应该清楚一点。我同意 self.__raw_data 通过将 raw_data 设为私有来修复外部可访问性。但是我想保护它免受其他对同一类中的数据进行操作的内部方法的影响。

标签: python oop properties pandas setter


【解决方案1】:

您在raw_data 设置器中所做的任何事情都不会停止直接分配给__raw_data。我建议不要定义 setter 并使用 __raw_data 进行初始化。这将阻止写入raw_data,但不会阻止__raw_data

如果您想要更严格的执法,那么按照设计,您没有太多选择。一种选择是用 C 或 Cython 编写您的课程。另一种选择更容易,但它有尴尬的副作用。该选项是子类化不可变的内置类型,例如tuple,并使用__new__ 创建预初始化实例,而不是使用__init__ 将它们变为初始化状态:

class Immutable(tuple):
    __slots__ = [] # Prevents creation of instance __dict__
    def __new__(cls, *whatever_args):
        attribute1 = compute_it_however()
        attribute2 = likewise()
        return super(cls, Immutable).__new__(cls, attribute1, attribute2)
    @property
    def attribute1(self):
        return self[0]
    @property
    def attribute2(self):
        return self[1]

这使您的对象不可变,但尴尬的副作用是您的对象现在是元组。

【讨论】:

  • 是的 - 谢谢。我可能只是编写一个简单的脚本来解析 python 源代码,检查 init 方法之外的任何__raw_data= 分配。那么我所需要的只是一个不可变的 pandas DataFrame?
  • @sanguineturtle:也许吧。我对 Pandas 不熟悉。
【解决方案2】:

你能得到的最接近的是只允许设置 self._raw_data 如果它还没有设置,即:

class Foo(object):
    def __init__(self, dataframe):
        self.raw_data = dataframe

    @property
    def raw_data(self):
         return getattr(self, '_raw_data', None)

    @raw_data.setter
    def raw_data(self, dataframe):
        if hasattr(self, '_raw_data'):
            raise AttributeError, "Attribute is read-only")
        self._raw_data = dataframe

这使得 setter 大多无用,因此您会得到相同的结果,而跳过它的代码更少(这将使属性成为只读):

class Foo(object):
    def __init__(self, dataframe):
        self._raw_data = dataframe

    @property
    def raw_data(self):
         return self._raw_data

但请注意,这些解决方案都不会阻止您直接设置_raw_data

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 2011-03-19
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多