全面学习Python魔法方法(magic methods) III
目录
全面学习Python魔法方法(magic methods) I
全面学习Python魔法方法(magic methods) II
全面学习Python魔法方法(magic methods) III
Copying
有时,特别是在处理可变对象时,您希望能够复制对象并进行更改,而不会影响您从中复制的内容。 这是Python的copy发挥作用的地方,但我们必须告诉Python如何有效地复制。
-
__copy__(self)
为类的实例定义
copy.copy()
的行为。copy.copy()
返回对象的浅拷贝{这意味着,虽然实例本身是一个新实例,但它的所有数据都被引用,即对象本身被复制,但其数据仍被引用(因此浅拷贝中的数据更改可能会导致原始更改)。 -
__deepcopy__(self, memodict=)
为类的实例定义
copy.deepcopy()
的行为。copy.deepcopy()
返回对象的深拷贝,对象及其数据都是copied.memodict
是一个以前复制的对象的缓存,这可以优化复制并防止在复制递归数据结构时无限递归。如果要深拷贝单个属性,请在该属性上调用copy.deepcopy()
,并将memodict
作为第一个参数。
与往常一样,在任何情况下,我们都需要比默认行为提供的更细粒度的控制。例如,如果试图复制一个将缓存存储为字典(可能很大)的对象,那么复制缓存可能也没有意义——如果缓存可以在实例之间在内存中共享。
Pickling
pickle是Python数据结构的序列化过程,当需要存储一个对象并稍后检索它时,它可能非常有用。pickle非常重要,因此它不仅有自己的模块(pickle),还具有自己的协议和相应的魔法方法。但是首先,简单介绍一下如何pickle现有类型。
Pickling: A Quick Soak in the Brine
让我们深入pickling。 假设有一个要稍后存储和检索的字典,可以将其内容写入文件,仔细确保编写正确的语法,然后使用exec()
或处理文件输入来检索它。
但这最是不危险的:如果以明文形式存储重要数据,则可能会以任何方式损坏或更改程序导致崩溃或更糟糕地在计算机上运行恶意代码。因此,我们要pickle数据:
1 | import pickle |
如果我们想要原来的数据,所要做的就是unpickle it:
1 | import pickle |
但是提醒的是:pickle并不完美。Pickle文件很容易在无意和有意的情况下被损坏。pickle可能比使用纯文本文件更安全,但它仍然可以用于运行恶意代码。它在不同版本的Python中也是不兼容的,所以不要期望发布pickle对象,也不要期望人们能够打开它们。但是,它也可以是缓存和其他常见序列化任务的强大工具。
Pickling your own Objects
Pickle不仅适用于内置类型。它适用于遵循pickle协议的任何类。pickle协议有四个可选方法供Python对象自定义它们的行为方式(对于C扩展,它有点不同,但这不在我们的范围内):
-
__getinitargs__(self)
如果想在类被打开时调用
__init__
,可以定义__getinitargs__
,它应该返回想要传递给__init__
的参数的元组。 请注意,此方法仅适用于旧式类 -
__getnewargs__(self)
对于新式类,可以影响在unpickling时传递给__new__
的参数。 此方法还应返回一个参数元组,然后传递给__new__
。 -
__getstate__(self)
不存储对象的
__dict__
属性,而是可以返回在对象被pickle时存储的自定义状态。当对象被打开时,__setstate__
将使用该状态。 -
__setstate__(self,state)
当对象被unpickled时,如果定义了__setstate__
,则对象的状态将被传递给它,而不是直接应用于对象的__dict__
。这与__getstate__
相同:当两者都被定义时,你可以用你想要的任何东西来表示对象的pickle状态。 -
__reduce__(self)
当定义扩展类型(即使用Python的C API实现的类型)时,如果想要pickle这些类型,则必须告诉Python如何pickle这些类型。
__reduce__()
在定义它的对象被pickle时被调用,它可以返回一个表示Python将查找和pickle的全局名称的字符串,或者一个元组。元组包含2到5个元素:一个可调用对象,用于重新创建对象,一个可调用对象的参数元组,一个要传递给
__setstate__
(可选)的状态,一个迭代器,产生要被pickle的列表项(可选)和一个迭代器,产生要被pickle的字典项(可选) -
__reduce_ex__(self)
如果它已定义,则
__reduce_ex__
将在pickle时调用__reduce__
。__reduce__
也可以定义为不支持__reduce_ex__
的旧版本的pickling API。
An Example
我们的例子是一个Slate,它记住它的值是什么以及何时写入它们的值。但是,每次进行pickle时,这个Slate都会变为空白:不会保存当前值。
1 | import time |
How to Call Magic Methods
Python中的一些魔法方法直接映射到内置函数; 在这种情况下,如何调用它们是相当明显的。但是,在其他情况下,调用就不那么明显了,让我们看一看一些不明显的语法,这些语法会导致调用魔法的方法。
魔法方法 | 被调用时 | 解释 |
---|---|---|
__new__(cls [,...]) |
instance = MyClass(arg1, arg2) |
__new__ is called on instance creation |
__init__(self [,...]) |
instance = MyClass(arg1, arg2) |
__init__ is called on instance creation |
__cmp__(self, other) |
self == other , self > other , etc. |
Called for any comparison |
__pos__(self) |
+self |
Unary plus sign |
__neg__(self) |
-self |
Unary minus sign |
__invert__(self) |
self |
Bitwise inversion |
__index__(self) |
x[self] |
Conversion when object is used as index |
__nonzero__(self) |
bool(self) |
Boolean value of the object |
__getattr__(self, name) |
self.name # name doesn’t exist |
Accessing nonexistent at tribute |
__setattr__(self, name, val) |
self.name = val |
Assigning to an attribute |
__delattr__(self, name) |
del self.name |
Deleting an attribute |
__getattribute__(self, name) |
self.name |
Accessing any attribute |
__getitem__(self, key) |
self[key] |
Accessing an item using an in dex |
__setitem__(self, key, val) |
self[key] = val |
Assigning to an item using an index |
__delitem__(self, key) |
del self[key] |
Deleting an item using an in dex |
__iter__(self) |
for x in self |
Iteration |
__contains__(self, value) |
value in self , value not in self |
Membership tests using in |
__call__(self [,...]) |
self(args) |
“Calling” an instance |
__enter__(self) |
with self as x: |
with statement context man agers |
__exit__(self, exc, val, trace) |
with self as x: |
with statement context man agers |
__getstate__(self) |
pickle.dump(pkl_file, self) |
Pickling |
__setstate__(self) |
data = pickle.load(pkl_- file) |
Pickling |