python魔法数_魔法函数

1.什么是魔法函数

在python中,有的名称以双下划线开头同时以双下划线结尾这种形式,

我们只知道它是python自己定义的,同时我们也不应该去定义类似的函数。

我们将“__init__”这种形式的函数成为魔法函数。"__init__"是构造器,用来初始化对象。

魔法函数不需要去显式的调用,同时魔法函数不能自定义。

魔法函数会被python隐式的去被调用。

举个简单的例子:

现在我们需要遍历对象中的属性,传统做法是取属性然后去遍历。

classPerson(object):def __init__(self,p_list):

self.p_list=p_list

person= Person(["ming","ke","mao"])for em inperson.p_list:print(em)

我们可以使用__getitem__来更简单的实现。classNewPerson(object):def __init__(self,p_list):

self.p_list=p_listdef __getitem__(self, item):returnself.p_list[item]

newPerson= NewPerson(["ming","kebi","mao"])#这里就不需要取属性了。

for em innewPerson:print(em)

我们可以通过不添加__getitem__,来知道__getitem__是将对象转换成可迭代对象。

#‘NewPerson‘ object is not iterable

在python中,只有可迭代对象才可以进行遍历,而可迭代对象必须拥有item()或者__item__方法。

当python在进行循环的时候,会去看对象是否由item()方法,如果没有会去看是否与__getitem__魔法函数,否则就不能迭代。

2.python魔法函数对python语法的影响

魔法函数会影响python语法本身。

示例一:

classNewPerson(object):def __init__(self,p_list):

self.p_list=p_list

newPerson= NewPerson(["ming","kebi","mao"])print(len(newPerson)) #TypeError: object of type ‘NewPerson‘ has no len()

print(len(newPerson[:])) #TypeError: ‘NewPerson‘ object is not subscriptable

对象没有长度和不能切片可以理解。

示例二:

classNewPerson(object):def __init__(self,p_list):

self.p_list=p_listdef __getitem__(self, item):returnself.p_list[item]

newPerson= NewPerson(["ming","kebi","mao"])print(len(newPerson)) #TypeError: object of type ‘NewPerson‘ has no len()

print(len(newPerson[:])) #3

newPerson之所以能够切片是因为__getitem__返回的是一个list,而list肯定可以切片

newPerson在取值的时候调用了__gititem__这个魔法方法,从而返回list,所以newPerson[]有len

示例三:

classNewPerson(object):def __init__(self,p_list):

self.p_list=p_listdef __getitem__(self, item):returnself.p_list[item]def __len__(self):returnlen(self.p_list)

newPerson= NewPerson(["ming","kebi","mao"])print(len(newPerson)) #3 调用__len__

print(len(newPerson[:])) #3 调用__getitem__

现在我们帮这个对象实现了__len__这个方法,所以这个newPerson对象可以可以直接使用len()

此时newPerson[:]因为是取值,依旧使用的是__getitem__这个方法。

3.魔法函数一览

使用dir()或者__dir__可以或者一个对象已经定义的的魔法函数。

例如:dir(Person)

__class__ 等同于type,打印对象类似

__delattr__

__dict__ 等同于vars,以键值对的形式返回对象的属性信息

__dir__

__doc__ 帮助文档

__eq__

__format__

__ge__

__getattribute__

__gt__

__hash__

__init__ 构造器

__init_subclass__

__le__

__lt__

__module__

__ne__

__new__

__reduce__

__reduce_ex__

__repr__

__setattr__

__sizeof__

__str__

__subclasshook__

__weakref__

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

1)非数学运算

(1)字符串

__repr__

__str__

(2)集合序列相关

__len__

__getitem__:将当前对象转换为可迭代对象,因而可以切片。

__setitem__

__delitem__

__contains__

(3)迭代相关

__iter__

__next__

(4)可调用

__call__

(5)with上下文管理器

__enter__

__exit__

(6)数值转换

__abs__

__bool__

__int__

__float__

__hash__

__index__

(7)元类相关

__new__

__init__

(8)属性相关

__getattr__:没有属性做什么

__setattr__

__getattribute__

__setattribute__

__dir__

(9)属性描述符

__get__

__set__

__delete__

(10)协程

__await__

__aiter__

__anext__

__aenter__

__aexit__

2)数学运算

(1)一元运算符

__neg__ (-)

__pos__ (+)

__abs__

(2)二元运算符

__lt__ (

__le__ (<=)

__eq__ (==)

__ne__ (!=)

__gt__ (>)

__ge__ (>=)

(3)算术运算符

__add__ (+)

__sub__ (-)

__mul__ (*)

__truediv__ (/)

__floordiv__ (//)

__mod__ (%)

__divmod__ 或divmod()

__pow__ 或pow() (**)

__round__ 或round()

(4)反向算术运算符

__radd__

__rsub__

__rmul__

__rtruediv__

__rfloordiv__

__rmod__

__rdivmod__

__rpow__

(5)增量赋值算术运算符

__iadd__

__isub__

__imul__

__ifloordiv__

__ipow__

(6)位运算符

__invert__ (~)

__lshift__ (<

__rshift__ (>>)

__and__ (&)

__or__ (|)

__xor__ (^)

(7)反向位运算符

__rlshift__

__rrshift__

__iand__

__ixor__

__ior__

(8)增量赋值运算符

__ilshift__

__irshift__

__iand__

__ixor__

__ior__

3)__str__、__repr__

classPerson(object):def __init__(self,p_list):

self.p_list=p_list

person= Person(["ming","UZI","karsa"])print(person) #<__main__.person object at>

print会隐式调用str,也就是__str__

现在可以修改一下__str__返回值。classPerson(object):def __init__(self,p_list):

self.p_list=p_listdef __str__(self):return ".".join(self.p_list) #默认return self

person = Person(["ming","UZI","karsa"])#本来是返回这个对象的内存地址,现在我们修改了返回值。

print(person) #ming.UZI.karsa

classPerson(object):def __init__(self,p_list):

self.p_list=p_list

person= Person(["ming","UZI","karsa"])

person#<__main__.person at>

隐式调用repr(person)classPerson(object):def __init__(self,p_list):

self.p_list=p_listdef __repr__(self):return "+".join(self.p_list)

person= Person(["ming","UZI","karsa"])

person#ming+UZI+karsa

反思:

我们在写代码的时候,比如定义a = 11,我们如果想获取它的绝对值,就会用abs(a)来进行获取。

此时我就会想为什么a就能用abs来获取绝对值了?因为它已经定义了

20190801130238478495.png

在init中定义了这个魔法方法,所以你才能够使用这些方法。

就像上面,如果我们没有定义__len__这个方法,那么按照常理是不能使用len(),

因为不支持,它是一个对象,对象里面原始定义也没有定义。

所以我们可以给它实现__len__这个魔法函数,person这个对象就可以使用了。

比如我们定义了一个类:

classNum(object):def __init__(self,value):

self.value=value

a= Num(1)print(abs(a)) #TypeError: bad operand type for abs(): ‘Num‘

现在a是一个新的类Num的对象,并不是int的对象,所以它是无法使用abs()的。

我们给它添加魔法函数__abs__之后就可以了。

classNum(object):def __init__(self,value):

self.value=valuedef __abs__(self):returnabs(self.value)

a= Num(1)print(abs(a))

比如我们再定义一个:

classMyVector(object):def __init__(self,x,y):

self.x=x

self.y=ydef __add__(self,other_instance):return MyVector(self.x + other_instance.x, self.y +other_instance.y)def __str__(self):return "x:{x}, y:{y}".format(x=self.x, y=self.y)

first_v= MyVector(1,2)

second_v= MyVector(3,4)print(first_v + second_v) #x:4, y:6

如果我们不定义__add__,那就是两个对象在加

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值