19

我正在做一些分布式计算,其中几台机器在假设它们都具有各种类的相同版本的情况下进行通信。因此,使这些类不可变似乎是一个不错的设计。并不是说它必须阻止怀有恶意的用户,它只是足够不变,以至于它永远不会被意外修改。

我该怎么办?例如,我将如何实现一个元类,使使用它的类在定义后不可变?

>>> class A(object):
...     __metaclass__ = ImmutableMetaclass
>>> A.something = SomethingElse # Don't want this
>>> a = A()
>>> a.something = Whatever # obviously, this is still perfectly fine.

替代方法也很好,例如接受一个类并返回一个不可变类的装饰器/函数。

4

3 回答 3

7

如果旧的使用技巧__slots__不适合你,这个或它的一些变体可以做到:只需编写__setattr__你的元类的方法作为你的后卫。在此示例中,我阻止分配新属性,但允许修改现有属性:

def immutable_meta(name, bases, dct):
    class Meta(type):
        def __init__(cls, name, bases, dct):
            type.__setattr__(cls,"attr",set(dct.keys()))
            type.__init__(cls, name, bases, dct)

        def __setattr__(cls, attr, value):
            if attr not in cls.attr:
                raise AttributeError ("Cannot assign attributes to this class")
            return type.__setattr__(cls, attr, value)
    return Meta(name, bases, dct)


class A:
    __metaclass__ = immutable_meta
    b = "test"

a = A()
a.c = 10 # this works
A.c = 20 # raises valueError
于 2011-02-15T01:39:08.703 回答
5

不要在不可变的类上浪费时间。

有些事情你可以做的比试图创建一个不可变对象要简单得多。

这里有五种不同的技术。您可以从中挑选。任何一个都会起作用。一些组合也会起作用。

  1. 文档。事实上,他们不会忘记这一点。给他们信用。

  2. 单元测试。__setattr__使用作为异常处理的简单模拟来模拟您的应用程序对象。对对象状态的任何更改都是单元测试中的失败。这很容易,不需要任何复杂的编程。

  3. 覆盖__setattr__以在每次尝试写入时引发异常。

  4. collections.namedtuple. 它们开箱即用是不可变的。

  5. collections.Mapping. 它是不可变的,但您确实需要实现一些方法才能使其工作。

于 2011-02-14T21:49:03.023 回答
1

如果您不介意重复使用他人的工作:

http://packages.python.org/pysistence/

不可变的持久(在功能上,而不是写到桌面意义上)数据结构。

即使您不按原样使用它们,源代码也应该提供一些灵感。例如,他们的 expando 类在其构造函数中获取一个对象并返回它的不可变版本。

于 2011-02-14T20:22:14.703 回答