什么是魔法函数?

所谓魔法函数(Magic Methods),是Python的一种高级语法,允许你在类中自定义函数(函数名格式一般为__xx__),并绑定到类的特殊方法中。比如在类A中自定义__str__()函数,则在调用str(A())时,会自动调用__str__()函数,并返回相应的结果。在我们平时的使用中,可能经常使用__init__函数和__del__函数,其实这也是魔法函数的一种。

魔法函数有什么作用?

魔法函数可以为你写的类增加一些额外功能,方便使用者理解。举个简单的例子,我们定义一个“人”的类People,当中有属性姓名name、年龄age。让你需要利用sorted函数对一个People的数组进行排序,排序规则是按照name和age同时排序,即name不同时比较name,相同时比较age。由于People类本身不具有比较功能,所以需要自定义,你可以这么定义People类:

class People(object):
def __init__(self, name, age):
self.name = name
self.age = age
return
def __str__(self):
return self.name + ":" + str(self.age)
def __lt__(self, other):
return self.name < other.name if self.name != other.name else self.age < other.age
print("\t".join([str(item) for item in sorted([People("abc", 18), People("abe", 19), People("abe", 12), People("abc", 17)])]))

上个例子中的__lt__函数即less than函数,即当比较两个People实例时自动调用。

再举个例子,实现一个可以任意深度赋值的字典类,如a[0] = 'value1'; a[1][2] = 'value2'; a[3][4][5] = 'value3'。这个和Python自带的defaultdict还有些区别。简单分析一下这个题目:普通的dict可以实现a[0]赋值,但是无法给a[1][2]直接赋值;后者赋值的过程大概为a.get(1).set(2, value),但我们不确定a[1]是否存在,所以很自然会想到要改写dict类中的__getitem__()函数,当a[1]不存在时,声明一个dict,并赋值给a[1]。代码如下:

class MyDict(dict):
def __setitem__(self, key, value): # 该函数不做改动,只是为了输出
print("setitem:", key, value, self)
super().__setitem__(key, value)
return

def __getitem__(self, item): # 主要技巧在该函数

print("getitem:", item, self)

# 基本思路: a[1][2]赋值时 需要先取出a[1] 然后给a[1]的[2]赋值

if item not in self: # 如果a[1]不存在

temp = MyDict() # 则需要新建一个dict

super().__setitem__(item, temp) # 并使得a[1] = dict

return temp # 返回a[1] 使得a[1][2] = value有效

return super().__getitem__(item) # 如果a[1]存在 则直接返回a[1]

# 使用例子:

test = MyDict()

test[0] = 'test'

test[1][2] = 'test1'

test[3][4][5] = 'test2'

Python中有哪些魔法函数?

Python中每个魔法函数都对应了一个Python内置函数或操作,比如__str__对应str函数,__lt__对应小于号

类的构造、删除:

object.__new__(self, ...)

object.__init__(self, ...)

object.__del__(self)

二元操作符:

+object.__add__(self, other)

-object.__sub__(self, other)

*object.__mul__(self, other)

//object.__floordiv__(self, other)

/object.__div__(self, other)

%object.__mod__(self, other)

**object.__pow__(self, other[, modulo])

<

>>object.__rshift__(self, other)

&object.__and__(self, other)

^object.__xor__(self, other)

|object.__or__(self, other)

扩展二元操作符:

+=object.__iadd__(self, other)

-=object.__isub__(self, other)

*=object.__imul__(self, other)

/=object.__idiv__(self, other)

//=object.__ifloordiv__(self, other)

%=object.__imod__(self, other)

**=object.__ipow__(self, other[, modulo])

<<=object.__ilshift__(self, other)

>>=object.__irshift__(self, other)

&=object.__iand__(self, other)

^=object.__ixor__(self, other)

|=object.__ior__(self, other)

一元操作符:

-object.__neg__(self)

+object.__pos__(self)

abs()object.__abs__(self)

~object.__invert__(self)

complex()object.__complex__(self)

int()object.__int__(self)

long()object.__long__(self)

float()object.__float__(self)

oct()object.__oct__(self)

hex()object.__hex__(self)

round()object.__round__(self, n)

floor()object__floor__(self)

ceil()object.__ceil__(self)

trunc()object.__trunc__(self)

比较函数:

<=object.__le__(self, other)

==object.__eq__(self, other)

!=object.__ne__(self, other)

>=object.__ge__(self, other)

>object.__gt__(self, other)类的表示、输出:

str()object.__str__(self)

repr()object.__repr__(self)

len()object.__len__(self)

hash()object.__hash__(self)

bool()object.__nonzero__(self)

dir()object.__dir__(self)

sys.getsizeof()object.__sizeof__(self)

类容器:

len()object.__len__(self)

self[key]object.__getitem__(self, key)

self[key] = valueobject.__setitem__(self, key, value)

del[key] object.__delitem__(self, key)

iter()object.__iter__(self)

reversed()object.__reversed__(self)

in操作object.__contains__(self, item)

字典key不存在时object.__missing__(self, key)

老规矩,文中代码整理后Push到Github:xianhu/LearnPython

=============================================================

欢迎大家拍砖、提意见。相互交流,共同进步!

==============================================================