3.8 KiB
3.8 KiB
如何用 Python 创建“不可变”的类
原文:https://www.blog.pythonlibrary.org/2014/01/17/how-to-create-immutable-classes-in-python/
我最近读了很多关于 Python 的神奇方法,最近还读了一些创建不可变类的方法。不可变类不允许程序员向实例添加属性(即猴子补丁)。如果我们实际上先看一个正常的类,会更容易理解一点。我们将从一个猴子补丁的例子开始,然后看一种使类“不可变”的方法。
猴子修补 Python 类
首先,我们需要创建一个可以玩的类。这里有一个简单的类,它不做任何事情:
########################################################################
class Mutable(object):
"""
A mutable class
"""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
pass
现在让我们创建这个类的一个实例,看看是否可以添加一个属性:
>>> mut_obj = Mutable()
>>> mut_obj.monkey = "tamarin"
>>> mut_obj.monkey
'tamarin'
这个类允许我们在运行时向它添加属性。现在我们知道了如何做一些简单的猴子补丁,让我们尝试阻止这种行为。
创建不可变的类
我读到的一个关于不可变类的例子提到,你可以通过用**_ _ 插槽 __** 替换一个类的 dict 来创建一个不可变类。让我们看看这是什么样子:
########################################################################
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)
现在我们只需要创建这个类的一个实例,看看我们是否可以用猴子来修补它:
>>> 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。让我们尝试更改其中一个属性:
>>> 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 文档
- stack overflow:python _ _ slots _ _
- 什么是插槽?