防止为类或模块创建新属性

Posted

技术标签:

【中文标题】防止为类或模块创建新属性【英文标题】:Prevent creating new attributes for class or module 【发布时间】:2020-04-10 02:01:08 【问题描述】:

我在 SO Prevent creating new attributes outside init 上看到了这个问题,它展示了如何防止向类的对象添加新属性。

我希望整个类甚至整个加载的模块都具有相同的行为。

示例类:

class Klass:
     a = 0
     b = 1

另一个模块:

from Klass import Klass

Klass.c = 2 # this should raise an error

这可能吗?

【问题讨论】:

【参考方案1】:

如果您试图阻止修改类本身,您可以创建一个为该类定义 __setattr__ 方法的元类。

class FrozenMeta(type):
    def __new__(cls, name, bases, dct):
        inst = super().__new__(cls, name, bases, "_FrozenMeta__frozen": False, **dct)
        inst.__frozen = True
        return inst
    def __setattr__(self, key, value):
        if self.__frozen and not hasattr(self, key):
            raise TypeError("I am frozen")
        super().__setattr__(key, value)

class A(metaclass=FrozenMeta):
    a = 1
    b = 2

A.a = 2
A.c = 1 # TypeError: I am frozen

【讨论】:

这在课堂上按预期工作!太糟糕了,整个模块都没有东西 @RoQuOTriX:查看this answer 了解将类变成模块的方法。【参考方案2】:

slots 的答案是 Pythonic 方式。

class Klass:
    __slots__ = ['a', 'b']

    def __init__(self, a=0, b=1):
        self.a = a
        self.b = b
>>> k = klass.Klass()
>>> k.a
0
>>> k.b
1
>>> k.c = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Klass' object has no attribute 'c'
>>>

【讨论】:

但是你仍然可以做 Klass.c=2 然后 k 也会有 c __slots__ 并非旨在防止创建属性,这只是一个副作用。

以上是关于防止为类或模块创建新属性的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 Firebase 中出现重复的用户属性?

当超链接行为由例如虚拟创建时,如何防止打开新选项卡或窗口? HTML 按钮的“点击”事件处理?

如何防止不需要的学说在symfony 4中持续存在?

防止在 iOS 5.0.1 中清除数据的文件属性?

笔记1

如何防止其他人在堆栈上创建您的类的新实例?