Python这些魔法方法和装饰器你都知道吗? O(≧▽≦)O Python小知识


本文现阶段会持续更新

魔法方法

在Python的类中有着很多如同__init__的魔法方法,其中我们最熟悉的__init__我就不再做赘述了。下列打魔法方法时因为避免和写博客使用的md语法的冲突,我会在双下划线前后输入空格。

__ len __

这也是一个比较常规的魔法方法了,用来输出类的长,其返回结果必须为整数

class Len:
    def __init__(self, lis):
        self.num = lis
    def __len__(self):
        print('调用len的时候这里会执行,其返回结果必须为整数,否则会报错')
        return len(self.num)
lis_len = [1, 2, 3, 4, 5]
print(len(Len(lis_len)))

__ new __

这个魔法方法是比较特别的,我们只要使用过Python的类(class),应该都知道self,哪self是如何生成的呢,这里就要牵扯到new方法了.
因为是生成self的方法,所以此方法中无需传入self,而是传入cls.

cls与self的区别

cls : 类对象本身
self : 实例化对象

class A:
    def __new__(cls, *args, **kwargs):
        print('我是new:', *args, id(cls))
        return object.__new__(cls)

    def __init__(self, *args):
        print('我是init:', *args, id(self))


a = A(1, 2, 3, 4)
print('大写A的id:', id(A), '小写a的id', id(a))

在这里插入图片描述
从上述代码中我们不难看出,cls代表的是实例化之前的,self代表的是实例化之后

Python派生内置不可变类型

使用这到例题来更深刻的理解__new__的不同.
要求:生成一个只包含正整数类型的元组.

  1. 首先要求为元组,所以我们建立继承元组的类IntTuple
  2. 这时候我们可以接受外部的内容来对元组内的内容进行筛选后在传入父类中
  3. 这里在实例化时就会将元组传入类中,而init魔法方法是在实例化才出现,如果我们在init中对元组过滤会失败,因为此时的元组已经被传入类中无法做改变,这时候就需要使用__new__进行过滤,说白了__new__就是用于生成self的
# Python派生内置不可变类型
class IntTuple(tuple):
    """"""
    def __new__(cls, all_tuple):
        int_tuple = [i for i in all_tuple if isinstance(i, int) and i > 0]
        return super().__new__(cls, int_tuple)


inttup = IntTuple((1, '12', '一二', -1, [1, 2], 2))
print(inttup)

在这里插入图片描述

__ enter __ 与 __ exit __

说道__ enter __ 与 __ exit __ 这两个魔法方法就不得不提’with’上下文管理器,这两个魔法方法会在调用with时启用。

class With:
    def __enter__(self):
        print('我是enter魔法方法')
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('我是exit方法')
def demo():
    print('demo')
with With():
    demo()
    demo()

在这里插入图片描述
这里exit方法中的三个属性,在程序运行正常时不会有任何输出,但是在程序出现错误时候,分别代表了 exc_type:错误类似;exc_val:错误内容;exc_tb:错误地址
在这里插入图片描述

__ lt __、 __ le __、 __ gt __、 __ ge __、 __ eq __、 __ ne __

让类比较大小,每个用于比较大小的方法中都会有两个属性,一个我们熟悉的self代表的是本身,另一个other代表的比较的对象

魔法方法 含义
__ lt __ 小于
__ le __ 小于等于
__ gt __ 大于
__ ge __ 大于等于
__ eq __ 等于
__ ne __ 不等于
# 类的比较大小
class Comparative:
    def __init__(self, items):
        self.__items = items
    def __lt__(self, other):
        print(self.__items, other.__items)
        return self.__items < other.__items
com1 = Comparative(1)
com2 = Comparative(2)
print(com1 < com2)

在这里插入图片描述
这里如果你想要将小于、小于等于、大于……等全部定义,需要定义六组,较为繁琐,这里推荐可以使用一个total_ordering装饰器,可以自动生成对应的对比。(total_ordering装饰器使用方式位于下方,常用装饰器中)

__ str __

__str__魔法方法会在类直接被打印的时候调用

# 魔法方法
class Magic:
    # __str__
    def __str__(self):
        return '我是魔法方法__str__'
print(Magic())

在这里插入图片描述

__ dict __ 与 __ dic __

__ dict __(动态绑定)魔法方法用于查看实例化后的对象有哪些实例属性.
__dic__魔法方法用于查看类中所以的方法和属性名
dict虽然只有属性,但通过dict可以看到属性中的值,dic只能看到方法名和属性名,没有值

class Magic:
    def __init__(self):
        self.test = None
magic = Magic()
print(magic.__dict__, '\n', magic.__dir__(), '\n', dir(magic))

在这里插入图片描述

__ slots __

节省内存时使用,用于去除动态绑定( __ dict __ )与弱引用( __ weakref __ )

# 节省内存__slots__
class dome1:
    def __init__(self, name, id, uid, password):
        self.name = name
        self.id = id
        self.uid = uid
        self.password = password

class dome2:
    __slots__ = ('name', 'id', 'uid', 'password')
    def __init__(self, name, id, uid, password):
        self.name = name
        self.id = id
        self.uid = uid
        self.password = password

data1 = dome1('寻觅', '1', '2', '123')
data2 = dome2('寻觅', '1', '2', '123')
print('dome1:', dir(data1), '\ndome2:', dir(data2), '\n', set(dir(data1)) - set(dir(data2)))

在这里插入图片描述

__ getattr __ 与 __ getattribute __

__ getattribute__除了会在__ getattr __ 之前调用,效果和调用方法都相同,大多数情况下使用 __ getattr __ 即可
__ getattr __会在找不到属性时调用

class Magic:
    def __init__(self, dic):
        self.__test = None
        self.dic = dic
    def __getattr__(self, item):
        return self.dic.get(item, '属性不存在')
test_dic = {'姓名': '寻觅', '性别': '男'}
magic = Magic(test_dic)
print('姓名:', magic.姓名)
print('年龄:', magic.年龄)

在这里插入图片描述

__ get __ 、 __ set __ 与 __ delete __

当只使用get一个方法时,称之为’非数据描述符’,其余情况下使用一个或多个get、set、delet方法时称之为’数据描述符’。
描述符一般写在一个单独类中,然后在需要的类中实例化描述符类

# 属性描述符(Descriptor)
class Descriptor:
    def __get__(self, instance, owner):
        print(instance, owner, '我是get')

    def __set__(self, instance, value):
        print(instance, value, '我是set')

    def __delete__(self, instance):
        print(instance, '我是delete')

# 魔法方法(Magic)
class Magic:
    dome = Descriptor()

magic = Magic()
magic.dome = 1
magic.dome
del magic.dome

在这里插入图片描述

属性查找顺序

算上属性描述符以及getattr ,以及有多重方式可以查找到属性了,但是如果在这些方式中出现相同的属性,查找的顺序如下

  1. __ getattribute __ 方法
  2. 输出属性描述符
  3. 输出类属性
  4. __ getattr __ 方法

常用装饰器

通过装饰器可以在不修改原函数的情况下最函数进行扩展

staticmethod(静态方法)

此方法在类中使用后,可以将类中的方法转变成为静态方法,转变成静态方法后最明显的就是方法中,没有了self属性
静态方法很少使用,因为静态方法和将方法直接写在类外效果相同,而大多数情况下都会选择后者.

class Decorator:
    def __init__(self):
        self.__test = None
    @staticmethod
    def static_test():
        return '测试'
decorator = Decorator()
print(decorator.static_test())

在这里插入图片描述

total_ordering(比较大小)

我们使用魔法方法比较大小需要创建六个方法,过程繁琐,这时如果我们使用total_ordering装饰器会大幅简化创建过程,只需寻找两组不同的比较(大于和小于这种属于一组)即可自动生成其余比较大小的方法。使用total_ordering我们需要先引入内置的functools库。

import functools

# 类的比较大小
@functools.total_ordering
class Comparative:
    def __init__(self, items):
        self.__items = items
    def __lt__(self, other):
        print(self.__items, other.__items)
        return self.__items < other.__items
    def __eq__(self, other):
        return self.__items == other.__items
com1 = Comparative(1)
com2 = Comparative(2)
print(com1 != com2, com1 >= com2)

在这里插入图片描述

property(方法变属性)与setter(修改属性)

将方法伪装成为属性使用,在get的时候非常有用。settrt修饰器格式为==@方法名.setter==

class Decorator:
    def __init__(self):
        self.__test = None

    @property
    def test(self):
        return self.__test

    @test.setter
    def test(self, data):
        self.__test = data

decorator = Decorator()
decorator.test = 2
print(decorator.test)

在这里插入图片描述

代码的GitHub位置

GitHub(https://github.com/xun-mi-git/Python-test)

发布了47 篇原创文章 · 获赞 23 · 访问量 3405

猜你喜欢

转载自blog.csdn.net/qq_39611230/article/details/103740622