Python进阶-----面对对象7.0(细谈__new__方法和__init__方法)

news2024/11/16 21:45:37

目录

前言:

__init__方法

__new__方法(重点!)

1.__new__方法的调用过程

2.重写__new__方法

3.__new__方法不同返回值的情况

3.单例模式


前言:

        上一期初步介绍了__new__()方法,但是实际上这个方法还有非常多的内容值得去讲一讲,学会了这个方法我们就可以去灵活把握控制我们对象的空间分配(上一期链接Python进阶-----面对对象6.0(绑定方法[类方法、静态方法]与内置方法)_Python欧尼酱的博客-CSDN博客),下面一期来看看吧!

__init__方法

这个方法对于大家应该是再熟悉不过了,是的,这是一个初始化方法也叫构造方法,当我们建立了一个新的对象之后,我们要对这个对象进行属性或者方法的初始化,这个方法是伴随着对象的建立而自动执行的。下面看一个示例:

class Person(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age  #定义实例化对象的属性
        print('person message')
dick=Person('Dick',18)
#输出结果:person message
print(dick.name,dick.age)
#输出结果:Dick 18

从这个例子就很容易看出,__init__方法是自动调用的,会自动输出person message,但是在此之前还有一个方法比__init__方法更加提前调用,那就是给对象分配空间__new__方法

__new__方法(重点!)

1.__new__方法的调用过程

        在Python中所有类的父类都是object类,object类也叫做超类,当我们创建了一个实例对象的时候,最先会去分配这个对象的内存空间,然后才可以往里面放入数据,这时候就会通过__new__方法去创建这个空间,然后返回这个对象空间给__init__方法再进行初始化.,也就是说__new__方法会返回这个空间传给__init__方法中的self实例参数,所以__new__方法也是跟__init__方法一样的会自动调用。

__new__ 方法是内置的静态类方法,python解释器在得到这个方法返回对象引用之后,将这个引用作为第一个参数传递给init方法所以new方法 比init方法执行要早   

 通俗的理解:

上面的说法可能会有点难理解,这里我做个比喻:在日常生活中,我们所用的木制家具是对木头进行加工处理而来的,__new__方法也就是一个伐木人,专门负责获取木材,然后把这些木材给__init__方法也就是木匠,木匠可以通过这些木材做出形形色色的家具供我们使用

        可能这里就会有人问,我每次定义了一个类的时候没有去定义__new__方法,只是定义了__init__方法,但是内存空间是怎么来的呢?

        answer:注意了,所有类都是继承了object类,所以当我们去给一个类写入内容的时候,实际上是对object类进行重写,__init__方法和__new__方法都是object类的方法,当我们去def __init__(self): 时,其实是对object里面的__init__方法进行重写,但是没有去def __new__(cls): 也就是说没有对__new__方法进行重写,那么我们所定义的这个类会保留并且调用这个方法,然后返回这个实例化对象的空间给__init__方法.

示例:

class A(object):
    def __init__(self,name):
        self.name=name
class B(object):
    object.__new__(object) #当我们没有重写__new__方法,默认继承并且调用object类__new__方法
    def __init__(self,name):
        self.name=name
user=A('dick')
user2=B("hao")
print(user.__sizeof__(),user2.__sizeof__()) #查看占内存
#输出结果:32 32

上面这个示例可以看出,类A和类B的效果是一模一样的,只是我把类B的__new__方法调用写出来了而已,所以实际上__new__方法会自动继承object类且调用的,无需我们去操心

注意:__new__方法是比__init__方法更加提前调用

 看个例子:

class User(object):
    def __init__(self,name):
        self.name=name
        print(f'我的名字是{self.name}')
    def __new__(cls, *args, **kwargs): #对__new__方法重写
        print('这个是__new__方法')
        return object.__new__(cls) #返回这个类对象的空间
jb=User('Dick')
#输出结果:
# 这个是__new__方法
# 我的名字是Dick

从输出结果就可以看出,是先输出__new__方法里面的内容,然后再输出__init__方法的内容,所以__new__方法是先执行的

2.重写__new__方法

        有时候我们不喜欢父类的__new__方法,所以我们会进行方法的重写,那么对这个方法的重写需要注意哪些东西呢?

我们去重写__new__方法时,是需要一个对象空间引索的返回值,这个返回值一般是使用父类的__new__方法 

 注意事项:

1.要有返回对这个对象的引用(也就是对象的空间)

2.要注意所返回的对象的类

示例1: 如果没有返回对象的引用会发生什么?

class A(object):
    def __new__(cls, *args, **kwargs):
        print('重写new方法')
    #这里我没有写返回值会怎么样呢?
    def __init__(self,name):
        print('初始化方法')
        self.name=name
user=A('dick')
print(user)
#输出结果:重写new方法
#         None

这里我没有返回值,当我创建了一个实例对象的时候是不知道这个分配的空间在哪里的,所以我无法对这个对象进行初始化,所以__init__方法无法执行,那么这个实例对象是没有获取到空间的,也就是说创建了一个空间,但是找不到这个空间在哪里,数据无法存入。

示例2:

class B(object):
    def __init__(self,name):
        self.name=name
        print('初始化方法')
    def __new__(cls, *args, **kwargs):
        print('这是new方法')
        return object.__new__(cls)
user=B('Dick')
print(user.name)
#输出结果:
# 这是new方法
# 初始化方法
# Dick

这的__new__方法有对象引索的返回值,会把当前类的实例化对象传给__init__方法中的self参数,然后进行初始化,所以这个对象可以获取到空间。

3.__new__方法不同返回值的情况

前面我们学习过了类方法,都知道类方法会有一个参数--cls,这个参数意思是表示这个类的本身,同样__new__方法也有一个cls参数,但是这个参数不一定是表示自身类的意思,还可以传入其他的父类。所以当这个参数有不同的传入值时,会发生不同的情况,下面就以代码作为示例一一讲解。

示例1:

class A(object):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        print('这个是A类重写的方法')
        res=object.__new__(cls)
        return res
class B(A):
    def __init__(self,sound):
        self.sound=sound
user=B('汪汪')
print(user.sound)
#输出结果:
# 这个是A的类
# 汪汪

这里A重写了object类中的__new__方法,B继承A,但是B没有重写A中的__new__方法,所以B是直接使用A中的__new__方法,传入当前类(cls),然后返回当前类(cls)实例化的空间

示例2:

class A(object):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        print('这个是A类重写的方法')
        res=object.__new__(cls)
        return res
class B(A):
    def __init__(self,sound):
        self.sound=sound
    def __new__(cls, *args, **kwargs):
        print('这个是B类重写的方法')
        res=cls.__new__(cls)  #这里是返回自身的实例对象空间引索
        return res
user=B('汪汪')
print(user.sound)
#结果:报错,进入死循环

 注意:重写__new__方法时,不能返回自身类对象的空间引索,否则会进入死循环

示例3: 

class A(object):
    jk='beauty'
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        res=object.__new__(cls)
        return res
    def fun(self):
        print('大家好!')
class B(A):
    def __init__(self,sound):
        self.sound=sound
    def __new__(cls, *args, **kwargs):
        res=super().__new__(A)  #返回的是类对象A的空间引索
        return res
user=B('汪汪') #实际上这里创建是类A的实例化对象
print(user.jk)  #输出结果:beauty
user.fun()  #输出结果:大家好!
print(user.sound) #报错'A' object has no attribute 'sound'
print(user.name)   #报错'A' object has no attribute 'name'

 这个例子是返回类A分配的空间引索,但是跟类B类型不同,所以无法进入到类B的__init__初始化,这也就导致了只有空间,但是没有初始化的情况,当我们去创建一个实例对象user的时候,user是一个类A的实例化对象,并不是类B的实例化对象。(这里的实例化对象user不经过类A的__init__初始化和类B__init__初始化)

3.单例模式

        单例模式是计算机非常常见的一种对象空间分配模式,比如:当我们在电脑点开设置窗口的时候,当我们再次点开这个设置窗口,计算机会检测这个窗口是否存在,如果存在的话就不会再次弹窗一个窗口,也就是说只有你把这个窗口叉掉后才会生成一个新的窗口,这样可以避免多个窗口的弹窗,同时还可以避免无效的内存占用(每次出现一个窗口是需要内存的),这个就叫做单例模式。

 Python中我们每次创建一个实例对象的时候都需要占用一个内存地址,在做项目的时候有些没有用的实例对象总是占用这地址导致程序运行缓慢。在Python中怎么去通过__new__方法来实现单例模式呢?我们往下看。

单例的好处: 节省内存

 代码如下:

class Student(object):
    _instance=None  #定义一个类属性,是可以在类中进行调用的
    def __init__(self, name,age):
        self.name=name
        self.age=age
    def __new__(cls, *args, **kwargs):
        if cls._instance is None: #如果这个内存为空的话就进行空间分配
            print('进行空间分配')
            cls._instance=super().__new__(cls)
        return cls._instance
Jack=Student('Jack',18)
John=Student('John',19)
Dick=Student('Dick',18)
print(Jack is Dick is John) #输出:True
print(Jack.name,Jack.age)   #输出:Dick 18
print(John.name,John.age)   #输出:Dick 18
print(Dick.name,Dick.age)   #输出:Dick 18

以上就是一个单例模式,这些实例化对象都是占用同一个内存地址,所以内存地址都是相同的,但是每次创建一个实例化对象,这个实例化对象会把是一个对象给覆盖掉,最后空间是属于最后一个实例化对象,故都是输出 Dick 18

 

 好了,以上就是本期的全部内容了,小伙伴们你们学会了怎么去分配对象的空间内存吗?

日常分享一张壁纸 :

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/390794.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统——18.进程互斥的软件实现方法

这篇文章我们来讲一下进程互斥的软件实现方法 目录 1.概述 2.单标志法 3.双标志检查法 4.双标志后检查法 5.Perterson算法 6.小结 1.概述 首先,我们来看一下这节的大体框架 学习提示: 理解各个算法的思想、原理结合上小节学习的“实现互斥的四个逻辑部分”…

通用业务平台设计(五):预警平台建设

前言 在上家公司,随着业务的不断拓展(从支持单个国家单个主体演变成支持多个国家多个主体),对预警的诉求越来越紧迫;如何保障业务的稳定性那?预警可以帮我们提前甄别风险,从而让我们可以在风险来临前将其消灭&#xff…

深度学习笔记:dropout和调优超参数方法

1 Dropout Dropout是一个常用于深度学习的减轻过拟合的方法。该方法在每一轮训练中随机删除部分隐藏层神经元。被删除的神经元不会进行正向或反向信号传递。在测试阶段所有神经元都会传递信号,但对各个神经元的输出要乘以训练时删除比例。 Dropout实现程序&#xf…

毕业设计 基于STM32单片机无线ZIGBEE智能大棚土壤湿度光照检测

基于STM32单片机无线ZIGBEE智能大棚土壤湿度光照检测1、项目简介1.1 系统构成1.2 系统功能2、部分电路设计2.1 STM32F103C8T6核心系统电路设计2.2 光敏采集电路设计2.3 温度采集电路设计3、部分代码展示3.1 读取DS18B20温度值3.2 定时器初始化1、项目简介 选题指导&#xff0c…

Learning Typescript and React in ts

目录 Basic typescript What is typescript? Configuring the TypeScript Compiler Fundamental build in types TypeScript Simple Types TypeScript Special Types Type: unknown Type: never Type: undefined & null Arrays Tuple Enums functions Ob…

Java集合专题

文章目录框架体系CollectionListArrayListLinkedListVectorSetHashSetLinkedHashSetTreeSetMapHashMapHashtableLinkedHashMapTreeMapPropertiesCollections框架体系 1、集合主要分了两组(单列集合,双列集合) 2、Collection接口有两个重要的子…

2.SpringSecurity认证

2.1登录校验流程 2.2认证原理 *源码流程: *自定义认证流程: *校验流程: *认证和校验连接: 2.3思路分析 *登录:

SQLI-Labs通关(2)5-7关

跟之前一样首先传参,然后查看注入点以及闭合 用and 11 and 12都没问题,接下来测试单引号 利用 and 12的时候会报错 利用order by来判断列数 得出一共三列 接下来就是联合查询 但是这个并不会回显 那么就利用盲注或者报错注入 在这里我们利用报错来测…

Vue3的生命周期函数

文章目录🌟 写在前面🌟 生命周期钩子函数🌟 组合式API生命周期🌟 写在最后🌟 写在前面 专栏介绍: 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章,应粉丝要求开始更新 Vue3 的相关技术文章&am…

OPPO 数据恢复:如何从 OPPO 手机恢复已删除的文件?

Oppo 手机以其精美的外观和拍摄的精美照片和视频而闻名。如果您不小心丢失了 OPPO 手机中珍贵的照片、视频等重要文件,并且为如何找回而苦恼,那么您来对地方了。我们其实有很多OPPO数据恢复方案,现在最重要的是尽快尝试这些方法,防…

Git 相关内容

目录 Git 相关流程和常用命令 Git workflow Git hooks Git 相关流程和常用命令 Git远程操作详解 - 阮一峰的网络日志 Git 使用规范流程 - 阮一峰的网络日志 常用 Git 命令清单 - 阮一峰的网络日志 Git workflow 啥玩意: 就是一个工作流程。可以比喻成一个河流…

用逻辑回归制作评分卡

目录 一.评分卡 二.导库,获取数据 三.探索数据与数据预处理 1.去除重复值 2.填补缺失值 3.描述性统计处理异常值 4.为什么不统一量纲,也不标准化数据分布 5.样本不均衡问题 6.分训练集和测试集 三.分箱 1.分多少个箱子才合适 2.分箱要达成什么…

Antlr4: 为parser rule添加label

1. parser rule中的label 1.1 简介 Antrl4语法文件Calculator.g4,stat和expr两个parser rule含有多个rule element,我们这两个parse rule的每个rule element添加了Alternative labels(简称label) 按照Antlr4的语法规则&#xff…

2022年显卡性能跑分排名表

2022年显卡性能跑分排名表(数据来源于快科技)这个版本的电脑显卡跑分榜第一的是NVIDIA GeForce RTX 3090 Ti显卡。由于显卡跑分受不同的测试环境、不同的显卡驱动版本以及不同散热设计而有所不同,所以显卡跑分会一直变化。 前二十名的台式电…

Linux(进程概念详解)

进程是如今编程领域非常重要的一个概念,进程是比较抽象的,不容易直接理解。因为进程与操作系统息息相关,因此在介绍进程之前,笔者打算先简易讲一下操作系统的工作流程,理解操作系统是如何管理软件和硬件的,…

垃圾收集器和内存分配(第五章)

《实战Java虚拟机:JVM故障诊断与性能优化 (第2版)》 Java 平台,标准版热点虚拟机垃圾回收调优指南 垃圾收集器虽然看起来数量比较多,但其实总体逻辑都是因为硬件环境的升级而演化出来的产品,不同垃圾收集器的产生总体可以划分为几…

智能优化算法应用:基于蚁狮优化算法的工程优化案例-附代码

智能优化算法应用:基于蚁狮算法的工程优化案例 文章目录智能优化算法应用:基于蚁狮算法的工程优化案例1.蚁狮算法2.压力容器设计问题3.三杆桁架设计问题4.拉压弹簧设计问题5.Matlab代码6.python代码摘要:本文介绍利用蚁狮搜索算法&#xff0c…

191、【动态规划】AcWing —— 900. 整数划分:完全背包解法+加减1解法(C++版本)

题目描述 参考文章:900. 整数划分 解题思路 因为本题中规定了数字从大到小,其实也就是不论是1 2 1 4,还是2 1 1 4,都会被看作是2 1 1 4这一种情况,因此本题是在遍历中不考虑结果顺序。 背包问题中只需考虑…

AcWing:并查集

并查集理论基础并查集的作用是什么:将两个集合合并。询问两个元素是否在一个集合当中。如果不使用并查集,要完成上述两个操作,我们需要:创建一个数组来表示某个元素在某个集合之中,如belong[x] a,即x元素在…

0201基础-组件-React

1 组件和模块 1.1 模块 对外提供特定功能的js程序,一般就是一个js文件 为什么拆分模块呢?随着业务逻辑增加,代码越来越多,越来越复杂。作用:复用js,简化js,提高js运行效率 1.2 模块化 当应用…