8

有没有一种方法可以通过覆盖__setattr__实例变量来防止或更改对 Python 中类变量的访问?

请注意,这个问题的标题有误,实际上是指实例变量,而不是类变量。

基于阅读有关(明显)死亡陷阱的多篇文章__slots__,我宁愿不走那条路(而且我还没有深入了解它是否符合我的要求)。

例子:

class A(object):

    foo = "don't change me"

    def __setattr__(self, name, value):
        raise ValueError

if __name__ == '__main__':
a1 = A()
print a1.foo # don't change me
print A.foo  # don't change me

A.foo = 'bar' # ideally throw an exception or something here
print A.foo   # bar
a2 = A()
print a1.foo  # bar
print a2.foo  # bar
4

2 回答 2

4

是的!你做的完全一样。

类上的__setattr__方法控制设置该类实例的属性。在 Python 中,一切都是对象。对象有类。因此,您只需将您的类安排为具有__setattr__方法的某个类的实例,就像您想要防止实例修改其属性时所做的那样!

类的类称为元类。默认元类是type:“类型的类型”或“类的类”。您希望创建一个type不允许设置其实例属性的子类(正如您object在实例级别创建一个不允许设置其实例属性的子类一样)。

class CantTouchThis(type):
    def __setattr__(cls, attr, value):
        raise Exception("NO!")

class SomeClass(object):
    __metaclass__ = CantTouchThis

仔细注意 的基类SomeClass之间的区别SomeClassSomeClass是 的子类object。它是 的一个实例CantTouchThis

几乎所有其他在实例级别工作的东西都可以类似地应用于具有元类的类级别;类只是像其他所有东西一样的实例。type由于(就像...等)的方法和实现,它们只有独特的优雅行为。

于 2012-10-16T11:35:22.033 回答
2

你快到了,你只需要将你的__setattr__方法移动到元类:

class ReadOnlyClass(type):
    def __setattr__(self, name, value):
        raise ValueError(name)
    
class A(object, metaclass=ReadOnlyClass):
    foo = "don't change me"
    
>>> a1 = A()
>>> a1.foo
"don't change me"
>>> A.foo
"don't change me"
>>> A.foo = 'bar'

Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    A.foo = 'bar'
  File "<pyshell#4>", line 3, in __setattr__
    raise ValueError, name
ValueError: foo
>>> print A.foo
don't change me
>>> a2 = A()
>>> a2.foo
"don't change me"
>>> a2.foo = 'x'
>>> a2.foo
'x'

请注意,尽管元类__setattr__阻止您更改类中的属性,但它不会阻止您使用实例属性隐藏它们:如果这是您想要的,那么您需要__setattr__在这两个地方进行定义。

编辑:更新为使用 Python 3.x 语法而不是古老的 Python 2.x

于 2012-10-16T11:23:33.530 回答