内容:
- 什么是魔法函数,如何增加类型的特性
- 不需要显示调用魔法函数,内置函数或相应python语法时会自动触发魔法函数
- 通过魔法函数去理解 python 类型
- len 内部有优化
一、什么是魔法函数
1、概念
魔法函数是一个网络术语,实际上属于Python的数据模型的概念
魔法函数:可以给你的类增加魔力的特殊方法一般满足两个条件:
- 1.双下划线开头,双下划线结尾:比如
__init__, __str__
等- 2.定制类的特性
- 魔法函数可以定义类的特性
- 魔法函数是解释器提供的功能
- 魔法函数只能使用 python 提供的魔法函数,不能自定义
2、示例
示例代码:
class Company:
def __init__(self, employee_list):
self.employee = employee_list
def __getitem__(self, index):
return self.employee[index]
company = Company(['alex', 'linda', 'catherine'])
employee = company.employee
for item in employee:
print(item)
# for 首先去找 __iter__, 没有时优化去找__getitem__
for item in company:
print(item)
运行结果:
alex
linda
catherine
alex
linda
catherine
进程已结束,退出代码为 0
二、Python的数据模型
Python官方文档
数据模型是不是我们经常说的数据类型?
其实不是,数据模型是对 Python 框架的描述,他规范了自身构建模块的接口,这些接口我们可以理解为是 Python 中的特殊方法,例如
__iter__
、__len__
、__del__
等。这些模块包括但不限于序列、迭代器、函数、类和上下文管理器。
假如我们在讨论,拥有哪些方法和属性的对象可以称为序列,实际上我们就是在讨论序列的数据模型。
数据模型,涉及到知识点其实就是魔法函数
- 魔法函数会影响 python 语法 company[:2]
- 魔法函数会影响内置函数调用 len(company)
三、魔法函数一览
我们将魔法方法分为:非数学运算和数学运算两大类。
1、 非数学运算
1.1 、字符串表示
- repr
- str
初识CV:字符串表示:__repr__函数和__str__函数:26
1.2、 集合、序列相关
- len
- getitem
- setitem
- delitem
- contains
初识CV:集合、序列相关:__len__函数、__getitem__函数、__setitem__函数、__delitem__函数和__contains__函数
1.3 、迭代相关
- iter
- next
初识CV:迭代相关:__iter__函数和__next__函数
1.4 、可调用
- call
初识CV:可调用:__call__函数
1.5 、with上下文管理器
- enter
- exit
初识CV:with上下文管理器:__enter__函数和__exit__函数
1.6 、数值转换
- abs
- bool
- int
- float
- hash
- index
示例代码;
class Num:
def __init__(self, num):
self.num = num
def __abs__(self):
return abs(self.num) # 如果改为return self.num ,那么示例代码的输出就是"-1"了
n = Num(-1)
print(abs(n))
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __str__(self):
return 'Vector(%s, %s)' % (self.x, self.y)
v1 = Vector(1, 3)
v2 = Vector(2, 4)
print(v1 + v2)
运行结果:
1
Vector(3, 7)
进程已结束,退出代码为 0
1.7 、元类相关
__new__函数和__init__函数:
1.8 、属性相关
__getattr__函数、__setattr__函数、__getattribute__函数、__setattribute__函数和__dir__函数:
1.9 、属性描述符
__get__函数、__set__函数和__delete_函数:
1.10、协程
__await__函数、__aiter__函数、__anext__函数、__aenter__函数和__aexit__函数
2、数学运算
2.1 、一元运算符
neg (-)、pos (+)和__abs__函数。
2.2 、二元运算符
lt (<)、le (<=)、eq (==)、ne (!=)、gt (>)和__ge__ (>=)。
2.3、 算术运算符
add (+)、sub (-)、mul (*)、truediv (/)、floordiv (//)、mod (%)、divmod 或divmod()、pow 或pow() (**)和__round__ 或round()。
2.4 、反向算术运算符
radd、rsub、rmul、rtruediv、rfloordiv、rmod、rdivmod__和__rpow。
2.5 、增量赋值算术运算符
iadd、isub、imul、ifloordiv__和__ipow。
2.6 、位运算符
- invert (~)
- lshift (<<)
- rshift (>>)
- and (&)
- or (|)
- xor (^)
2.7、 反向位运算符
- rlshift
- rrshift
- iand
- ixor
- ior
2.8 、增量赋值运算符
- ilshift
- irshift
- iand
- ixor
- ior
3、 其他魔法函数
- unicode
- delattr
- del
- dict
- all
四、len 函数的特殊性(举例说明魔法函数的重要性)
CPython时,向list,dict等内部做过优化,len(list)效率高
len函数不仅仅调用__len__方法这么简单,len函数对于set dict list等Python原生数据结构做了内部的优化,其性能是非常高的。应为原生数据结构中,会有一个专门的字段来储存数据长度,那么len函数会直接去读取这个字段,而不会去遍历它。
PS:一篇博客的回答:
• len()函数并不简单是一个类似于__len__()的方法
• len()函数内部做了很多的优化
• 尽量的去使用Python的内部函数