__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 的公共或私有属性。所有属性都是公共的。有一个习俗用一个前导下划线命名“私有”属性;这会警告任何使用你的对象的人,他们正在搞乱某种实现细节,但如果他们需要并且愿意接受风险,他们仍然可以这样做。