geekdoc-python-zh/docs/pythonlibrary/how-to-create-immutable-cla...

101 lines
3.8 KiB
Markdown

# 如何用 Python 创建“不可变”的类
> 原文:<https://www.blog.pythonlibrary.org/2014/01/17/how-to-create-immutable-classes-in-python/>
我最近读了很多关于 Python 的神奇方法,最近还读了一些创建不可变类的方法。不可变类不允许程序员向实例添加属性(即猴子补丁)。如果我们实际上先看一个正常的类,会更容易理解一点。我们将从一个猴子补丁的例子开始,然后看一种使类“不可变”的方法。
### 猴子修补 Python 类
首先,我们需要创建一个可以玩的类。这里有一个简单的类,它不做任何事情:
```py
########################################################################
class Mutable(object):
"""
A mutable class
"""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
pass
```
现在让我们创建这个类的一个实例,看看是否可以添加一个属性:
```py
>>> mut_obj = Mutable()
>>> mut_obj.monkey = "tamarin"
>>> mut_obj.monkey
'tamarin'
```
这个类允许我们在运行时向它添加属性。现在我们知道了如何做一些简单的猴子补丁,让我们尝试阻止这种行为。
### 创建不可变的类
我读到的一个关于不可变类的例子提到,你可以通过用**_ _ 插槽 __** 替换一个类的 **__dict__** 来创建一个不可变类。让我们看看这是什么样子:
```py
########################################################################
class Immutable(object):
"""
An immutable class
"""
__slots__ = ["one", "two", "three"]
#----------------------------------------------------------------------
def __init__(self, one, two, three):
"""Constructor"""
super(Immutable, self).__setattr__("one", one)
super(Immutable, self).__setattr__("two", two)
super(Immutable, self).__setattr__("three", three)
#----------------------------------------------------------------------
def __setattr__(self, name, value):
""""""
msg = "'%s' has no attribute %s" % (self.__class__,
name)
raise AttributeError(msg)
```
现在我们只需要创建这个类的一个实例,看看我们是否可以用猴子来修补它:
```py
>>> i = Immutable(1, 2, 3)
>>> i.four = 4
Traceback (most recent call last):
File "", line 1, in <fragment>AttributeError: 'Immutable' object has no attribute 'four'
```
在这种情况下,该类不允许我们对实例进行猴子修补。相反,我们收到一个 AttibuteError。让我们尝试更改其中一个属性:
```py
>>> i = Immutable(1, 2, 3)
>>> i.one = 2
Traceback (most recent call last):
File "c:\Users\mdriscoll\Desktop\rep-fonts\immutable\immute_slots.py", line 1, in ########################################################################
File "c:\Users\mdriscoll\Desktop\rep-fonts\immutable\immute_slots.py", line 33, in __setattr__
raise AttributeError(msg)
AttributeError: '<class>' has no attribute one
```
这是因为我们已经覆盖了 **__setattr__** 方法。如果你想的话,你可以重写这个方法,什么都不做。这将阻止追溯的发生,但也防止值被更改。如果您喜欢明确说明正在发生的事情,那么提出一个错误可能是一种方法。
如果你读了一些关于插槽的书,你会很快发现不鼓励以这种方式使用插槽。为什么?因为槽主要是作为内存优化而创建的(它减少了属性访问时间)。
您可以通过以下链接了解更多关于插槽的信息:
* 关于插槽的 Python [文档](http://docs.python.org/2/reference/datamodel.html?highlight=__slots__#slots)
* stack overflow:[python _ _ slots _ _](http://stackoverflow.com/q/472000/393194)
* 什么是插槽?
https://stackoverflow.com/questions/472000/python-slots