如何防止直接设置实例属性?

Posted

技术标签:

【中文标题】如何防止直接设置实例属性?【英文标题】:How to prevent setting instance attribute directly? 【发布时间】:2021-08-05 00:16:50 【问题描述】:

假设我有一个 A 类

class A:
    __slots__ = ['_x']

    def __init__(self):
         self._x = 10
    
    @property
    def x(self):
        return self._x

并且我想限制从除其他实例的方法之外的任何地方分配给a._x

我该怎么做?这在 Python 中是否可行?

问题是要编写一个类,其属性只能在特定方法内更改,而不能直接从外部更改。

【问题讨论】:

这能回答你的问题吗? How to restrict setting an attribute outside of constructor? 【参考方案1】:

Python 并没有像 C++ 这样的“私有”变量。即使您使用来自PEP8 的_ 前缀将变量设置为私有(正如您所做的那样)。您始终可以使用A._x 访问该变量。

如果您出于某种原因想要模拟私有变量,您可以使用__(双下划线)前缀,因为它会破坏名称。同样,您可以使用@property 装饰器来创建getter 和setter 函数并防止访问该属性。但是,即使这些也失败了,因为您可以使用 __dict__ 直接访问变量。

所以 Pythonic 的方式是保持原样。 Python 在这方面就像 perl。套用 Perl 书中关于隐私的一句名言,

哲学是你应该远离客厅,因为 你没有被邀请,不是因为它有霰弹枪防御。

【讨论】:

嗯,我对 Python 并不完全陌生,并且熟悉这种哲学。然而,在这种特殊情况下,我正在寻找一种解决方法。有点你想做的事情只是因为。作为练习:) 但我想如果可能的话它已经实施了。谢谢你阻止我浪费时间:)【参考方案2】:

我完全同意@kinshukdua 的观点。但是,只是为了探索更多可用的选项。您可以通过放置一些条件来覆盖 setattr

这可能不是最 Pythonic 的方式,但我愿意采用更清洁的方式来实现这一点。

class A:
    _x = 10 #dont think you need an init method since you are not adding any data
    def __setattr__(self, key, value):
        if 'yes' in value[1]:
            super().__setattr__(key,value[0])
        else:
            raise TypeError('You should not have access to this')

    def change(self, value,loc= 'yes'):
        self._x = value,loc
        return self._x
        
    
    

【讨论】:

我实际上想到了元编程来解决这个问题。就像创建一个为它创建 Lock 对象和上下文管理器并将其附加到类实例然后覆盖 setattr 魔术方法的元类,因此只有在 Lock 打开时才能添加和分配属性。在“new”调用期间执行所有这些操作,然后在 init 或其他方法调用期间使用锁分配其他属性。

以上是关于如何防止直接设置实例属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止特征 FEATURE_SECURE_PROCESSING 设置为 true 的 TransformerFactory 剥离属性?

在单个 AppDomain 上运行多个应用程序实例时如何防止属性覆盖?

[Effective JavaScript 笔记]第44条:使用null原型以防止原型污染

属性和实例变量的最佳实践

访问属性和访问实例变量的区别

OC 直接使用使用实例变量和通过属性来访问实例变量的区别