魔术方法及单例模式

目录

 

一。__new__方法和__init__:

二。重写__new__()方法的应用场景:单例模式

        思路:

        1.定义一个类属性,用来记录该类是否被创建过对象。

         2.在__new__()方法中对类属性做判断:

                1.若没创建过类,就创建一个,并保存起来,再修改类属性的值。

                2.若创建过了,就将之前创建的返回出去。

   3.装饰器实现单例模式

                被装饰器装饰的类,是单例类。

三。__str__()方法和__repr__()方法: 

1.内置函数str(),print(),format()处理对象时,都会触发对象对应的__str__方法。

2.内置函数repr()处理对象时,会触发对象对应的__repr__方法。

四。__call__()方法

        1.如果想类创建出来的对象可以像函数一样+()就能被调用,就需要在类中定义__call__方法

       2. 通过类来实现装饰器:

                在类中实现__call__()方法

     



魔术方法(魔法方法,特殊方法):

魔术方法都是Python内部定义的,不用自己去定义的类似__init__()这种双下划线开头或结尾的方法。

一。__new__方法和__init__:

__new__方法在父类object中已经实现,若子类中再出现,就属于重写父类中的方法;
new方法是用来创建对象的,应该返回一个对象,若不return一个对象,init方法无法执行,没有对象可初始化。
创建对象是Python中内置实现的,
我们无法实现,此时重写new方法时,可以直接通过:
   1.super().方法名;
   2.父类名.方法名;
来调用父类中的方法,通过父类的new方法创建对象并返回给我们

 在创建对象的时候自动调用__init__()方法内部的代码,对创建的对象进行初始化设置。

class MyClass(object):

    def __init__(self, name):
        """创建对象时会自动初始化对象属性"""
        print('这是init方法')
        self.name = name
        print("__init__的self.name", self.name)

    def __new__(cls, *args, **kwargs):
        """
        new一个对象,比__init__方法先执行
         __new__方法在父类object中已经实现,若子类中再出现,就属于重写父类中的方法;
         new方法是用来创建对象的,应该返回一个对象,创建对象是Python中内置实现的,
         我们无法实现,此时重写new方法时,可以直接通过:
            1.super().方法名;
            2.父类名.方法名;
         来调用父类中的方法,通过父类的new方法创建对象并返回给我们
        """
        print('这是new方法')
        # 此处若不return一个对象,init方法无法执行,因为没有对象可初始化
        # return object.__new__(cls)
        return super().__new__(cls)  

if __name__ == '__main__':
    m = MyClass('春田')
# 输出:
这是new方法
这是init方法
__init__的self.name
春田

二。重写__new__()方法的应用场景:单例模式

        比如我们有个配置类,不管哪里调用用的都是同一个配置,我们不管在哪个模块中导入这个类,在创建对象的时候,用的都是之前创建的同一个配置类的对象,不会在不同的地方单独创建对象了,所以可用单例模式实现类,这样就可以节省内存空间。

        思路:

        1.定义一个类属性,用来记录该类是否被创建过对象。

         2.在__new__()方法中对类属性做判断:

                1.若没创建过类,就创建一个,并保存起来,再修改类属性的值。

                2.若创建过了,就将之前创建的返回出去。

单例模式:

class Test(object):
    """
    如果类属性 __instance为None,则创建一个对象,并且将 __instance赋值为这个对象的引用,
    保证下次调用这个方法能知道这个类已经创建过对象了,这样就保证了始终只有1个对象。
    """
    __instance = None  # 设置一个类属性,用来记录该类有没有创建过对象

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:  # 如果没有对象(cls就是类本身)
      # if Test.__instance is None:  # 效果同上
            # 创建一个,并赋值给cls.__instance保存
            cls.__instance = super().__new__(cls)
            # 返回对象
            return cls.__instance
        else:
            # 返回对象
            return cls.__instance


if __name__ == '__main__':
    a = Test()
    b = Test()
    print(id(a))  # 输出:140505293127392
    print(id(b))  # 输出:140505293127392
    a.name = "春田"
    print(b.name) # 输出:春田

   3.装饰器实现单例模式

                被装饰器装饰的类,是单例类。

# 装饰器实现单例模式,被装饰的类,无论实例化多少次都只有一个对象。
def single(func):

    __instance = {}  # __instance 用来记录是否存在对象

    def wrapper(*args, **kwargs):
        if func not in __instance:  # 判断是否存在对象
            __instance[func] = func(*args, **kwargs)
            return __instance[func]
        else:
            return __instance.get(func)
    return wrapper


@single
class Test(object):

    def add(self):
        print('方法名是:add')


if __name__ == '__main__':
    t = Test()
    print(t)
    print(id(t))  # 输出:4517363520
    t2 = Test()
    print(id(t2))  # 输出:4517363520
    t.add()  # 输出:方法名是:add

三。__str__()方法和__repr__()方法: 

1.内置函数str(),print(),format()处理对象时,都会触发对象对应的__str__方法。

        使用str,print,format处理对象会优先触发__str__方法,在没定义__str__方法时,

        再去找__repr__方法,如果都没有,会再去找父类的__str__方法。

2.内置函数repr()处理对象时,会触发对象对应的__repr__方法。

        使用repr方法或在交互环境下输入变量,会先找自身的__repr__方法,自身没有__repr__方法

        时,再去找父类的__repr__方法。

class MyClass(object):

    def __init__(self, name):
        self.name = name

    def __str__(self):
        print('---str---方法触发了')
        return self.name  # __str__方法必须返回字符串,否则type错误。

    def __repr__(self):
        print('---repr---方法触发了')
        return '对象类型是{}'.format(self.name)  # __repr__方法必须返回字符串,否则type错误。


if __name__ == '__main__':
    m = MyClass('春田')
    # print,str,format函数会触发对象的__str__方法
    print(m)            # 输出:
                            # ---str - --方法触发了
                            # 春田
    # repr函数会触发对象的__repr__方法
    res = repr(m)
    print(res)          # 输出:
                            # ---repr - --方法触发了
                            # 对象类型是春田

四。__call__()方法

        1.如果想类创建出来的对象可以像函数一样+()就能被调用,就需要在类中定义__call__方法

class MyClass(object):

    def __init__(self, name):
        self.name = name

    def __call__(self, *args, **kwargs):
        print('---call--方法触发了')  # 对象在像函数一样被调用时触发__call__方法。


if __name__ == '__main__':
    m = MyClass("春田")
    m()  # 像函数一样调用对象。
         # 输出: ---call--方法触发了

       2. 通过类来实现装饰器:

                在类中实现__call__()方法

import time


class Timer(object):
    """通过类实现装饰器"""

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        st = time.time()
        time.sleep(2)
        self.func(*args, **kwargs)
        time.sleep(2)
        et = time.time()
        print('{}函数执行耗时:{}'.format(self.func.__name__, et - st))


@Timer
def func(a, b):
    return a + b


if __name__ == '__main__':
    func(1, 2)  # 输出:func函数执行耗时:4.010028839111328

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chuntian_tester

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值