Python中必须掌握的魔术方法!不知道你就太low了!

与__getattr__(self, name)不同,__setattr__ 是一个封装的解决方案。无论属性是否存在,它都允许你定义对对属性的赋值行为,以为这你可以对属性的值进行个性定制。实现__setattr__时要避免”无限递归”的错误。

__delattr__

与 __setattr__ 相同,但是功能是删除一个属性而不是设置他们。实现时也要防止无限递归现象发生。

__getattribute__(self, name)

__setitem__(self, key, value)

当你执行self[key] = value时,调用的是该方法。

__delitem__(self, key)

定义当一个项目被删除时的行为(比如 del self[key])。这只是可变容器协议中的一部分。当使用一个无效的键时应该抛出适当的异常。

__iter__(self)

返回一个容器迭代器,很多情况下会返回迭代器,尤其是当内置的iter()方法被调用的时候,以及当使用for x in container:方式循环的时候。迭代器是它们本身的对象,它们必须定义返回self的__iter__方法。

__reversed__(self)

实现当reversed()被调用时的行为。应该返回序列反转后的版本。仅当序列可以是有序的时候实现它,例如对于列表或者元组。

__contains__(self, item)

定义了调用in和not in来测试成员是否存在的时候所产生的行为。你可能会问为什么这个不是序列协议的一部分?因为当__contains__没有被定义的时候,如果没有定义,那么Python会迭代容器中的元素来一个一个比较,从而决定返回True或者False。

__missing__(self, key)

dict字典类型会有该方法,它定义了key如果在容器中找不到时触发的行为。比如d = {‘a’: 1}, 当你执行d[notexist]时,d.__missing__[‘notexist’]就会被调用。

一个例子

下面是书中的例子,用魔术方法来实现Haskell语言中的一个数据结构。

# -*- coding: utf-8 -*-
class FunctionalList:
 ''' 实现了内置类型list的功能,并丰富了一些其他方法: head, tail, init, last, drop, take'''
 def __init__(self, values=None):
 if values is None:
 self.values = []
 else:
 self.values = values
 def __len__(self):
 return len(self.values)
 def __getitem__(self, key):
 return self.values[key]
 def __setitem__(self, key, value):
 self.values[key] = value
 def __delitem__(self, key):
 del self.values[key]
 def __iter__(self):
 return iter(self.values)
 def __reversed__(self):
 return FunctionalList(reversed(self.values))
 def append(self, value):
 self.values.append(value)
 def head(self):
 # 获取第一个元素
 return self.values[0]
 def tail(self):
 # 获取第一个元素之后的所有元素
 return self.values[1:]
 def init(self):
 # 获取最后一个元素之前的所有元素
 return self.values[:-1]
 def last(self):
 # 获取最后一个元素
 return self.values[-1]
 def drop(self, n):
 # 获取所有元素,除了前N个
 return self.values[n:]
 def take(self, n):
 # 获取前N个元素
 return self.values[:n]

允许一个类的实例像函数一样被调用。实质上说,这意味着 x() 与 x.__call__() 是相同的。注意 __call__ 的参数可变。这意味着你可以定义 __call__ 为其他你想要的函数,无论有多少个参数。

__call__ 在那些类的实例经常改变状态的时候会非常有效。调用这个实例是一种改变这个对象状态的直接和优雅的做法。用一个实例来表达最好不过了:

定义了当一个代码块被执行或者终止后,会话管理器应该做什么。它可以被用来处理异常、执行清理工作或做一些代码块执行完毕之后的日常工作。如果代码块执行成功,exceptiontype,exceptionvalue,和traceback将会为None。否则,你可以选择处理这个异常或者是直接交给用户处理。如果你想处理这个异常的话,请确保__exit在所有语句结束之后返回True。如果你想让异常被会话管理器处理的话,那么就让其产生该异常。

# -*- coding: UTF-8 -*-
class Meter(object):
 """
 对于单位"米"的描述器
 """
 def __init__(self, value=0.0):
 self.value = float(value)
 def __get__(self, instance, owner):
 return self.value
 def __set__(self, instance, value):
 self.value = float(value)
class Foot(object):
 """
 对于单位"英尺"的描述器
 """
 def __get__(self, instance, owner):
 return instance.meter * 3.2808
 def __set__(self, instance, value):
 instance.meter = float(value) / 3.2808
class Distance(object):
 """
 用米和英寸来表示两个描述器之间的距离
 """
 meter = Meter(10)
 foot = Foot()

使用时:

>>>d = Distance()
>>>print d.foot
>>>print d.meter
32.808
10.0

复制

有时候,尤其是当你在处理可变对象时,你可能想要复制一个对象,然后对其做出一些改变而不希望影响原来的对象。这就是Python的copy所发挥作用的地方。

__copy__(self)

定义了当对你的类的实例调用copy.copy()时所产生的行为。copy.copy()返回了你的对象的一个浅拷贝——这意味着,当实例本身是一个新实例时,它的所有数据都被引用了——例如,当一个对象本身被复制了,它的数据仍然是被引用的(因此,对于浅拷贝中数据的更改仍然可能导致数据在原始对象的中的改变)。

__deepcopy__(self, memodict={})

定义了当对你的类的实例调用copy.deepcopy()时所产生的行为。copy.deepcopy()返回了你的对象的一个深拷贝——对象和其数据都被拷贝了。memodict是对之前被拷贝的对象的一个缓存——这优化了拷贝过程并且阻止了对递归数据结构拷贝时的无限递归。当你想要进行对一个单独的属性进行深拷贝时,调用copy.deepcopy(),并以memodict为第一个参数。

附录

用于比较的魔术方法

数值计算的魔术方法

单目运算符和函数

双目运算符或函数

增量运算

类型转换

进群:125240963 即可获取源码哦!
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页