__setattr__ 如何处理类属性?

2024-02-13

我想确切地了解如何__setattr__与类属性一起使用。当我试图覆盖时出现这个问题__setattr__以防止属性被写入简单的类中。

我的第一次尝试使用实例级属性,如下所示:

class SampleClass(object):
    
    def __init__(self):
        self.PublicAttribute1 = "attribute"

    def __setattr__(self, key, value):
        raise Exception("Attribute is Read-Only")

我原本以为只有外部尝试设置属性才会抛出错误,但即使是里面的语句__init__导致抛出异常。

后来我最终找到了另一种方法来做到这一点,同时尝试解决不同的问题。我最终得到的是:

class SampleClass(object):
    PublicAttribute1 = "attribute"

    def __setattr__(self, key, value):
        raise Exception("Attribute is Read-Only")

我期望得到相同的结果,但令我惊讶的是,我能够设置类属性,同时防止在初始声明后进行更改。

我不明白为什么这会起作用。我知道这与类变量和实例变量有关。我的理论是使用__setattr__在类变量上将创建一个同名的实例变量,因为我相信我以前见过这种行为,但我不确定。

谁能准确解释这里发生了什么?


__setattr__()仅适用于该类的实例。在你的第二个例子中,当你定义PublicAttribute1,你在类上定义它;没有实例,所以__setattr__()不被调用。

注意:在 Python 中,您可以使用.符号称为属性,而不是变量。 (在其他语言中,它们可能被称为“成员变量”或类似名称。)

如果您在实例上设置同名的属性,则类属性将被隐藏,这是正确的。例如:

class C(object):
    attr = 42

 c = C()
 print(c.attr)     # 42
 c.attr = 13
 print(c.attr)     # 13
 print(C.attr)     # 42

Python 通过首先查看实例来解析属性访问,如果实例上没有该名称的属性,它会查找实例的类,然后查找该类的父类,依此类推,直到找到object,Python 类层次结构的根对象。

所以在上面的例子中,我们定义attr在课堂上。因此,当我们访问c.attr(实例属性),我们得到 42,类的属性值,因为实例上没有这样的属性。当我们设置实例的属性后,然后打印c.attr我们再次获得刚刚设置的值,因为实例上现在有一个具有该名称的属性。但价值42仍然作为类的属性存在,C.attr,正如我们看到的第三个print.

设置实例属性的语句__init__()方法由 Python 处理,就像在对象上设置属性的任何代码一样。 Python 不关心代码是在类的“内部”还是“外部”。那么,你可能会想,如何才能绕过“保护”呢?__setattr__()什么时候初始化对象?简单:你调用__setattr__()没有这种保护的类的方法(通常是父类的方法),并将其传递给您的实例。

所以不要写:

self.PublicAttribute1 = "attribute"

你必须写:

 object.__setattr__(self, "PublicAttribute1", "attribute")

由于属性存储在实例的属性字典中,因此命名为__dict__,您还可以绕过您的__setattr__直接写到:

 self.__dict__["PublicAttribute1"] = "attribute"

这两种语法都是丑陋且冗长的,但是您可以相对轻松地破坏您尝试添加的保护(毕竟,如果您可以做到这一点,那么其他人也可以)可能会导致您得出这样的结论:Python 不会对受保护的属性有很好的支持。事实上并非如此,这是设计使然。 “我们都是同意的成年人。”您不应该考虑 Python 的公共或私有属性。所有属性都是公共的。有一个习俗用一个前导下划线命名“私有”属性;这会警告任何使用你的对象的人,他们正在搞乱某种实现细节,但如果他们需要并且愿意接受风险,他们仍然可以这样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

__setattr__ 如何处理类属性? 的相关文章

随机推荐