前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python 魔术方法(二) 对象的创建与单例模式的实现

python 魔术方法(二) 对象的创建与单例模式的实现

作者头像
用户3147702
发布2022-06-27 13:24:05
3770
发布2022-06-27 13:24:05
举报
文章被收录于专栏:小脑斧科技博客

1. 引言

上一篇文章中,我们详细介绍了 Python 中的几个最常用的魔术方法。 python 魔术方法(一) 自定义容器类与类属性控制

但上一篇文章中没有介绍 Python 创建对象的两个魔术方法 — __new__ 与 __init__,而这两者的区别却常常困扰着很多 Python 开发人员。 本文我们就来详细讲解他们的区别和用法。

2. 基本介绍

2.1. __init__

__init__ 方法作为类似于其他面向对象语言中构造函数的存在,是十分常用的,我们通常在 __init__ 方法中放入对象的初始化工作。

代码语言:javascript
复制
def __init__(self)

2.2. __new__

与 __init__ 方法不同,__new__ 方法必须具有一个返回值,返回所创建对象的实例。

代码语言:javascript
复制
def __new__(cls, *args, **kwargs)

3. 调用时机

代码语言:javascript
复制
class TechlogTest:
    def __init__(self):
        print('Techlog __init__')

    def __new__(cls, *args, **kwargs):
        print('Techlog __new__')
        return object.__new__(cls, *args, **kwargs)

if __name__ == '__main__':
    testobj = TechlogTest()

运行结果如下:

Techlog __new__ Techlog __init__

可以看到,__new__ 方法在 __init__ 方法前被调用,加上 __new__ 方法必须返回当前类的实例,我们就可以知道他们的区别了。 __new__ 方法担负了对象的创建工作,而 __init__ 方法则在对象完成创建后对该对象进行必要的初始化工作。 同时,__new__ 方法的首个参数是 cls,实际上他是一个属于类的静态方法,这也是我们能够通过 object.__new__ 的方法来调用他的原因。

4. 通过 __new__ 实现单例模式

因为 __new__ 方法担负了所有类对象的创建,因此我们可以通过实现 __new__ 方法就可以控制类对象的创建流程。 单例模式就是一个很好的例子。

4.1. 单例模式

我们曾经介绍过单例模式: 单例模式 — Singleton java 实现单例的各种方式

他保证了一个类仅有一个实例,并且提供访问这个实例的全局访问方式。 很多情况下,保证一个类同时最多只有一个实例是非常必要的,例如项目中的线程池组件,之所以使用线程池,往往是为了降低反复创建、销毁线程的开销,如果项目中维护多个线程池将是很令人头疼的一件事。 有时,一个类也并没有必要存在多个实例,例如对于线程安全的类来说,一个实例可以处理并发环境下的所有请求,如果为每一个请求单独创建一个类实例,那么会造成很大程度上的资源浪费。

4.2. python 实现单例模式

代码语言:javascript
复制
class SingleTon:
    _instance = {}

    def __new__(cls, *args, **kwargs):
        if cls not in cls._instance:
            cls._instance[cls] = super(SingleTon, cls).__new__(cls, *args, **kwargs)
        return cls._instance[cls]

上面这个类通过一个类成员 _instance 保存各个类型的单例实例,我们通过继承 SingleTon 类就可以实现单例模式了。 继承到子类中的 __new__ 方法确保了无论如何创建,都保证只获取到一个对象,而 _instance 作为一个 dict 让我们可以同时创建多个单例模式类型。

4.3. 示例

代码语言:javascript
复制
class SingleTon:
    _instance = {}

    def __new__(cls, *args, **kwargs):
        if cls not in cls._instance:
            cls._instance[cls] = super(SingleTon, cls).__new__(cls, *args, **kwargs)
        return cls._instance[cls]

class TechTest(SingleTon):
    testfield = 12

if __name__ == '__main__':
    tech01 = TechTest()
    tech02 = TechTest()
    print(tech01)
    print(tech02)

打印出了:

<__main__.TechTest object at 0x000001E40736A710> <__main__.TechTest object at 0x000001E40736A710>

可以看到,两个对象的地址是一模一样的,他们实际上是同一个对象。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 引言
  • 2. 基本介绍
    • 2.1. __init__
      • 2.2. __new__
      • 3. 调用时机
      • 4. 通过 __new__ 实现单例模式
        • 4.1. 单例模式
          • 4.2. python 实现单例模式
            • 4.3. 示例
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档