首页 > 名字大全 > 微信名字 正文
【魔法微信名字】如何正确使用python高级——魔法方法?(下图)

时间:2023-03-05 13:34:45 阅读: 评论: 作者:佚名

微信搜索关注“水滴和银弹”公众号,首次获得优质技术干货。用7年的资深后端研发,用简单的方式明确说明技术。

上一句python高级——中如何正确使用魔法方法?(上图)主要介绍了配置和初始化、类表示、访问控制等魔法方法、使用场景。

这句话,我们主要继续介绍剩下的魔法方法:比较操作、容器类操作、可调用对象、序列化等。

比较操作

比较工作的魔法方法主要有:

_ _ CMP _ _ _ _ _ _ EQ _ _ _ _ _ _ LT _ _ _ _ _ GT _ _ _ _ _ _ CMP _ _

从名字中我们可以看出这种魔法方法的作用。需要比较两个对象时,可以为比较操作定义__cmp__。

Class person(对象):

Def__init__(self,uid):

=uid

Def _ _ CMP _ _ (self,其他):

If==o:

Return0

Ifo:

Return1

Return-1

P1=Person(1)

P2=Person(2)

Printp1p2#False

Printp1p2#True

Printp1==p2#False

从例子中我们可以看到比较两个对象的具体逻辑。

如果__cmp__返回大于0的整数(通常为1),如果说明self other __cmp__返回大于0的整数(通常为-1),说明self other为_;在比较谁时,我想使用属性B进行比较,此时__cmp__这个逻辑不能很好地实现,所以只适用于一般的比较逻辑。

那么如何实现复杂的比较逻辑呢?

为此,__eq__、__ne__、__lt__、__gt__

#coding:utf8

Class person(对象):

Def _ _ init _ _ (self,uid,name,salary) :

=uid

=name

=salary

Def _ _ eq _ _ (self,其他):

'对象==判断'''

Return==o

Def _ _ ne _ _ (self,其他):

对象!=判断''''

丽顿!=o

Def _ _ lt _ _ (self,其他):

对象“”的判断基于len(名称)“”

Returnlen()len)

Def _ _ gt _ _ (self,其他):

对\ "\ "对象的判断基于alary \ "\ "

利图罗

P1=Person(1,' zhangsan '1000)

P2=Person(1,' lisi '2000)

P3=Person(1,' wangwu '3000)

Printp1==p1#uid是否相同

Printp1!=p2#uid是否不同

Printp2p3#name长度比较

Printp3p2#salary比较

__eq__

__eq__如前一句所述,您可以与__hash__方法一起检查两个对象是否相同。

但是,在本例中,在判断两个对象是否相同时,实际上会比较名为uid的属性。

__ne__

同样,当需要判断两个对象不相等时,将调用__ne__方法。在这种情况下,根据uid判断。

__lt__

判断一个对象是否比另一个对象小时,将调用__lt__方法。此示例根据name的长度进行比较。

__gt__

同样,在判断一个对象是否大于另一个对象时,将调用__gt__方法。此示例根据salary属性进行判断。

在python 3中,__cmp__因与其他魔法方法在功能上很重而被取消

复。

容器类操作

接下来我们来看容器类的魔法方法,主要包括:

  • __setitem__
  • __getitem__
  • __delitem__
  • __len__
  • __iter__
  • __contains__
  • __reversed__
  • 是不是很熟悉?我们在开发中多少都使用到过这些方法。

    在介绍容器的魔法方法之前,我们首先想一下,Python 中的容器类型都有哪些?

    是的,Python 中常见的容器类型有:

  • 字典
  • 元组
  • 列表
  • 字符串
  • 这些都是容器类型。为什么这么说?

    因为它们都是「可迭代」的。可迭代是因为,它们都实现了容器协议,也就是我们下面要介绍到的魔法方法。

    我们看下面这个例子。

    # coding: utf8 class MyList(object):     """自己实现一个list"""     def __init__(self, values=None):         # 初始化自定义list          = values or []     def __setitem__(self, key, value):         # 添加元素         [key] = value     def __getitem__(self, key):         # 获取元素         return [key]     def __delitem__(self, key):         # 删除元素         del [key]     def __len__(self):         # 自定义list的元素个数         return len()     def __iter__(self):         # 可迭代         return self     def next(self):         # 迭代的具体细节         # 如果__iter__返回self 则必须实现此方法         if  >= len():             raise StopIteration()         value = []          += 1         return value     def __contains__(self, key):         # 元素是否在自定义list中         return key in      def __reversed__(self):         # 反转         return list(reversed()) # 初始化自定义list my_list = MyList([1, 2, 3, 4, 5]) print my_list[0]      # __getitem__ my_list[1] = 20       # __setitem__ print 1 in my_list      # __contains__ print len(my_list)      # __len__ print [i for i in my_list]  # __iter__ del my_list[0]              # __del__ reversed_list = reversed(my_list) # __reversed__ print [i for i in reversed_list]  # __iter__

    在这个例子中,我们自己实现了一个 MyList 类,在这个类中,定义了很多容器类的魔法方法。这样一来,我们这个 MyList 类就可以像操作普通 list 一样,通过切片的方式添加、获取、删除、迭代元素了。

    __setitem__

    当我们执行 my_list[1] = 20 时,就会调用 __setitem__ 方法,这个方法主要用于向容器内添加元素。

    __getitem__

    当我们执行 my_list[0] 时,就会调用 __getitem__ 方法,这个方法主要用于从容器中读取元素。

    __delitem__

    当我们执行 del my_list[0] 时,就会调用 __delitem__ 方法,这个方法主要用于从容器中删除元素。

    __len__

    当我们执行 len(my_list) 时,就会调用 __len__ 方法,这个方法主要用于读取容器内元素的数量。

    __iter__

    这个方法我们需要重点关注,为什么我们可以执行 [i for i in my_list]?就是因为我们定义了 __iter__。

    这个方法的返回值可以有两种:

  • 返回 iter(obj):代表使用 obj 对象的迭代协议,一般 obj 是内置的容器对象
  • 返回 self:代表迭代的逻辑由本类来实现,此时需要重写 next 方法,实现自定义的迭代逻辑
  • 在这个例子中,__iter__ 返回的是 self,所以我们需要定义 next 方法,实现自己的迭代细节。

    next 方法使用一个索引变量,用于记录当前迭代的位置,这个方法每次被调用时,都会返回一个元素,当所有元素都迭代完成后,这个方法会返回 StopIteration 异常,此时 for 会停止迭代。

    在 Python3 中,已不再使用 next 方法,取而代之的是 __next__。

    __contains__

    从名字也能看出来,这个方法是在执行 1 in my_list 时触发,用于判断某个元素是否存在于容器中。

    __reversed__

    这个方法在执行 reversed(my_list) 时触发,用于反转容器的元素,具体的反转逻辑我们也可以自己实现。

    可调用对象

    了解了容器类魔法方法,我们接着来看可调用对象的魔法方法,这个魔法方法只有一个:__call__。

    我们看下面这个例子。

    # coding: utf8 class Circle(object):     def __init__(self, x, y):          = x          = y     def __call__(self, x, y):          = x          = y c = Circle(10, 20)  # __init__ print c.x, c.y     # 10 20 c(100, 200)         # 调用instance() 触发__call__ print c.x, c.y      # 100 200

    仔细看这个例子,我们首先初始化一个 Circle 实例 c,此时会调用 __init__ 方法,这个很好理解。

    但是,我们对于实例 c 又做了调用 c(100, 200),注意,此时的 c 是一个实例对象,当我们这样执行时,其实它调用的就是 __call__。这样一来,我们就可以把实例当做一个方法来执行。

    如果不好理解,你可以多看几遍这个例子,理解一下。

    也就是说,Python 中的实例,也是可以被调用的,通过定义 __call__ 方法,就可以传入自定义参数实现自己的逻辑。

    这个魔法方法通常会用在类实现一个装饰器、元类等场景中,当你遇到这个魔法方法时,你能理解其中的原理就可以了。

    序列化

    我们知道 Python 提供了序列号模块 pickle,当我们使用这个模块序列化一个实例时,也可以通过魔法方法来实现自己的逻辑,这些魔法方法包括:

  • __getstate__
  • __setstate__
  • 我们来看下面的例子。

    # coding: utf8 class Person(object):     def __init__(self, name, age, birthday):          = name          = age          = birthday     def __getstate__(self):         # 执行  时 忽略 age 属性         return {             'name': ,             'birthday':          }     def __setstate__(self, state):         # 执行  时 忽略 age 属性          = state['name']          = state['birthday'] person = Person('zhangsan', 20, date(2017, 2, 23)) pickled_person = (person) # __getstate__ p = (pickled_person) # __setstate__ print p.name, p.birthday print p.age # AttributeError: 'Person' object has no attribute 'age'

    __getstate__

    在这个例子中,我们首先初始了 Person 对象,其中包括 3 个属性:name、age、birthday。

    当我们调用 (person) 时,__getstate__ 方法就会被调用,在这里我们忽略了 Person 对象的 age 属性,那么 person 在序列化时,就只会对其他两个属性进行保存。

    __setstate__

    同样地,当我们调用 (pickled_person) 时,__setstate__ 会被调用,其中入参就是 __getstate__ 返回的结果。

    在 __setstate__ 方法,我们从入参中取得了被序列化的 dict,然后从 dict 中取出对应的属性,就达到了反序列的效果。

    其他魔法方法

    好了,以上介绍的这些,就是我们平时遇到比较多的魔法方法。

    剩下的魔法方法还有很多,主要包括数值处理、算术操作、反射算术操作、增量赋值、类型转换、反射这几类,由于我们在开发中很少会见到,这里就不再过多介绍了,当遇到时,我们直接查阅文档了解即可。

    总结

    这篇文章,我们主要介绍了关于比较操作、容器类、可调用对象、序列化等魔法方法。

    其中,比较操作的魔法方法,可以用于自定义实例的比较逻辑。容器类魔法方法,可以帮我们实现一个自定义的容器类,然后我们就可以像操作 list、dict 那样,方便地去获取容器里的元素、迭代数据等等。可调用对象魔法方法,可以把一个实例当做方法来调用。序列化的魔法方法,可以修改一个实例的序列化和反序列化逻辑。

    Python 的魔法方法正如它的名字一样,如果使用得当,我们的类就像被添加了魔法一样,变得更易用。我们可以使用这些魔法方法,帮我们实现一些复杂的功能,例如装饰器、元类等等。

    微信搜索关注「水滴与银弹」公众号,第一时间获取优质技术干货。7年资深后端研发,用简单的方式把技术讲清楚。

    • 评论列表

    发表评论: