python中的魔法函数

一.简介


魔法函数总览

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

1.Python中以双下划线(__xx__)开始和结束的函数为魔法函数。

2.调用类实例化的对象的方法时自动调用魔法函数。

3.在自己定义的类中,可以实现之前的内置函数。

作用:

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

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

二.详细介绍

我们将魔法方法分为:非数学运算和数学运算两大类。

1.非数学运算

1.1字符串表示

__repr__函数和__str__函数:

函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式,某对象没有适于人阅读的解释形式的话,str() 会返回repr(),所以print展示的都是str的格式。

__repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。

1.2集合、序列相关

__len__函数、__getitem__函数、__setitem__函数、__delitem__函数和__contains__函数:

a. __ len__函数

在Python中,如果你调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的__len__()方法。

b.__getitem__函数

Python的特殊方法__getitem_() 主要作用是可以让对象实现迭代功能。我们通过一个实例来说明。

定义一个Sentence类,通过索引提取单词。

测试

通过测试发现,示例s可以正常迭代。但是没有定义getitem() 测试则会报错,TypeError: '***' object is not iterable。

序列可以迭代:

我们都知道序列是可以迭代,下面具体说明原因。

解释器需要迭代对象x时, 会自动调用iter(x)方法。内置的 iter(x) 方法有以下作用:

1.检查对象是否实现了__iter__ 方法,如果实现了就调用它(也就是我们偶尔用到的特殊方法重载),获取一个迭代器。

2.如果没有实现iter()方法, 但是实现了 __getitem__方法,Python会创建一个迭代器,尝试按顺序(从索引0开始)获取元素。

3.如果尝试失败,Python抛出TypeError异常,通常会提示TypeError: '***' object is not iterable。

任何Python序列都可迭代的原因是,他们都实现了__getitem__方法。其实,标准的序列也都实现了__iter__方法。

注意:从python3.4 开始,检查对象x能否迭代,最准确的方法是: 调用iter(x)方法,如果不可迭代,在处理TypeError异常。这比使用isinstance(x,abc.Iterable)更准确,因为iter()方法会考虑到遗留的__getitem__()方法,而abc.Iterable类则不考虑。

c. __ setitem__函数

__setitem__(self,key,value):该方法应该按一定的方式存储和key相关的value。在设置类实例属性时自动调用的。


d. __ delitem__()

__delitem__(self,key):

这个方法在对对象的组成部分使用__del__语句的时候被调用,应删除与key相关联的值。同样,仅当对象可变的时候,才需要实现这个方法。

e. __contains__函数

在Class里添加__contains__(self,x)函数,可判断我们输入的数据是否在Class里.参数x就是我们传入的数据。

1.3迭代相关


__iter__函数和__next__函数:

Iterator: 迭代器(当然也是Iterable),同时实现了__iter__和__next__的对象,缺少任何一个都不算是Iterator,迭代器都能被for循环遍历。

必须同时实现__iter__和__next__


Iterable: 有迭代能力的对象,实现了__next__,那么就认为它有迭代能力。

注释掉了__iter__依然可用next调用


生成器iterator就是个元素懒加载的容器,生成器与迭代器本质是一样的,只是实现方式不一样,生成器是在函数定义里写一行yield或者使用生成式列表生成(如(i fori in range(5)))。

1.4可调用

__ call__函数

该方法的功能类似于在类中重载 () 运算符,使得类实例对象可以像调用普通函数那样,以“对象名()”的形式使用。作用:为了将类的实例对象变为可调用对象。

可以看到,通过在 CLanguage 类中实现 __call__() 方法,使的 clangs 实例对象变为了可调用对象。


1.5 数值转换

__abs__函数、__bool__函数、__int__函数、__float__函数、__hash__函数和__index__函数:

1.6元类相关

__new__函数和__init__函数

实际上,__init__函数并不是真正意义上的构造函数,__init__方法做的事情是在对象创建好之后初始化变量。真正创建实例的是__new__方法。

我们来看下面的例子

上面的代码中实例化了一个Person对象,可以看到__new__和__init__都被调用了。__new__方法用于创建对象并返回对象,当返回对象时会自动调用__init__方法进行初始化。__new__方法是静态方法,而__init__是实例方法。

1、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别。

2、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例。

3、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。

4、如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是 cls 来保证是当前类实例,如果是其他类的类名;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数。

5、在定义子类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。


1.7属性相关

__getattr__函数、__setattr__函数、__getattribute__函数、__setattribute__函数和__dir__函数:


1.8属性描述符

__get__函数、__set__函数和__delete_函数:

1.9协程

__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__()函数:

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容