Python的self作用,以及__init__,__new__

news2024/11/24 19:04:49

本章来探讨一下Python类的self作用,以及__init__,__new__。

为什么是探讨,不是学习,因为菜🐎;

先看个例子:

class Example:
    def animal(self):
        self.dog = "大黄"

    def Dog(self):
        print(self.dog)

if __name__ == "__main__":
    example = Example()
    example.Dog()

运行报错:AttributeError: 'Example' object has no attribute 'dog'

这个报错是告诉你,Example类没有这个属性。

先来看看self

self是一个惯用的命名约定,它代表类的实例对象自身。在类的方法中,self作为第一个参数传递,并用于引用该实例对象的属性和方法。

注意了,这里说到了实例对象

当定义一个类并创建该类的实例时,每个实例都有自己的状态(即属性)和行为(即方法)。在方法中,可以使用self来引用当前实例对象的属性和方法。

也就是上述代码中的self.dog。

白话文一点就是我在这个类中定义了创建了一个该类的实例后,我就可以全局使用。不论定义多少个方法,都可以使用这个实例。


如何解决,找不到属性的问题?

1、返回self.dog这个值
2、写一个方法中可以规避这个问题 3、写到__init__中
4、动态添加

1、2不说了,看__init__。以及动态加载

写到__init__中

class Example:
    def __init__(self) -> None:
        self.dog = "大黄"

    def Dog(self):
        print(self.dog)

if __name__ == "__main__":
    example = Example()
    example.Dog()

这样就没啥问题了。但是还有一种写法。

class Example:
    def __init__(self, dog) -> None:
        self.dog = dog
        
    def Dog(self):
        print(self.dog)

if __name__ == "__main__":
    example = Example("大黄")
    example.Dog()

这样也是OK的,二者有什么区别?

def __init__(self, dog)

这种写法有一个形参。所以在实例化的时候必须要传参。

动态加载

class Example:
    def set_name(self, dog):
        self.dog = dog
        
    def Dog(self):
        print(self.dog)

if __name__ == "__main__":
    example = Example()
    example.set_name("大黄")
    example.Dog()

__init__方法用于初始化实例的属性,也叫初始化方法。

在使用过程中,我们只知道__init__用于初始化。如果没有在__init__中定义的属性,就不能在其他方法中被使用。

实例化分为两阶段:
○ 构造实力过程,实例化 先调__new__
○ 初始化过程,初始化 再调__init__

这里提到了__new__。


再来看看实例对象。

前面说了self的作用。那么它什么时候作为第一个参数传递?

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

    def say_hello(self):
        print(f"Hello, my name is {self.name}.")

person = Person('清安')
# 相当于Person.say_hello(person)
person.say_hello()

person.say_hello()相当于调用Person类的say_hello方法,并把person实例对象自动作为第一个参数传递给该方法。也就是说,self在say_hello方法中会接收到person对象的引用,从而可以访问person对象的属性和方法。这个过程中,person对象被传递给了self。

所以

class Person:

    def __init__(self, name, age=18):
        print('__init__ id is ',id(self))
        self.name = name
        self.age = age

    def show(self):  # self永远指向当前实例自身,this
        print(f"show id is {id(self)}")
        print(f"{self.name} is {self.age} yeas old!")

pe = Person('拾贰', 20)  # 实例化
pe.show()   # 相当于show(pe)  解释器会把pe赋值给self
print(f"id is {id(pe)}")

__init__ id is 2064008937088 show id is 2064008937088
拾贰 is 20 yeas old!
id is 2064008937088

好了,已经知道self的由来了

__init__小结

__init__方法中初始化了self.属性名,使其成为实例的属性。

self在Python类中是一个引用,用于指代实例对象本身。通过self,您可以在类的方法中访问和操作实例对象的属性和方法。

最后来个错误的例子再次熟悉熟悉

class Person:

    def __init__(self, age=18):
        self.age = age

    def show(self):
        return 1
        
pe = Person('清安', 20).show()
print(pe)
TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given
类型错误:__init__()接受1到2个位置参数,但给定了3个

再来看看__new__

__init__方法在创建实例对象时自动调用,且在该方法中定义的属性会被添加到实例对象中。

前面也提到了几个注意点,结合这里的自动调用,我们就很有必要看看__new__了。

_new__方法在类实例化时起到了重要的作用,它负责创建并返回类的实例对象。在创建实例对象之前,__new__方法被调用,它接收类作为第一个参数,并返回一个新的实例对象。

当你不手动创建的时候,它就自动,但你手动的时候,那就看看下面的例子。

class Example:
    def __new__(cls):
        instance = super().__new__(cls)
        instance.name = "清安"  # 手动创建实例属性name
        return instance

    def print_name(self):
        print(f"Name: {self.name}")

example = Example()
example.print_name() # Name: 清安

cls参数代表的是类本身也就是Example

当调用Example()时,实际上是调用了Example类的构造方法__new__,它会创建一个Example类的实例对象,并把这个实例对象的引用返回。

上述中return了instance,所以,我们在self的时候其实就是example实例对象的引用。这也就是self其实也就是一个参数,仅此而已。


在代码中我们instance.name = "清安",也就等价于在__init__中写了self.name = '清安'。

而代码中是super(),super()函数用于获取当前类的父类,并返回一个代理对象,可以调用父类的方法和属性。在这个例子中,super().__new__方法,并传递当前类cls作为参数。


来复刻一下object has no attribute。

class Example:
    def __new__(cls):
        instance = super().__new__(cls)
        instance.name = "清安"  # 手动创建实例属性name
        return instance

    def print_name(self):
        print(f"Name: {self.name}")

    # def print_age(self):
    #     print(f"Age: {self.age}")  # 尝试访问未定义的属性age

example = Example()
example.print_name()
example.print_age()   # 报错:AttributeError: 'Example' object has no attribute 'age'

__new__与__init__区别

__new__方法和__init__方法在类实例化时起到不同的作用。__new__方法负责创建并返回实例对象,而__init__方法负责对实例对象进行初始化。


个题外话的例子

class ClassA:
    def __new__(cls):
        instance_b = ClassB()  # 在__new__方法中创建ClassB的实例
        instance_a = super().__new__(cls)
        instance_a.class_b = instance_b  # 将ClassB的实例赋值给当前类的属性
        return instance_a

    def __init__(self):
        pass

class ClassB:
    def __init__(self):
        self.name = "B"

    def __str__(self):
        return self.name

obj_a = ClassA()
print(obj_a.class_b)  # 输出:B

此处没啥说的

class Example:
    def __init__(self,age=0) -> None:
        self.age = age
    
    def print_name(self):
        self.age += 1
        return self

example = Example().print_name()
print(example.age)

上述代码注释return self,运行即AttributeError: 'NoneType' object has no attribute 'age'

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

推荐书籍

618,清华社 IT BOOK 多得图书活动开始啦!活动时间为 2023 年 6 月 7 日至 6 月 18 日,清华 社为您精选多款高分好书,涵盖了 C++、Java、Python、前端、后端、数据库、算法与机器学习等多 个 IT 开发领域,适合不同层次的读者。全场 5 折,扫码领券更有优惠哦!快来京东点击链接(https://pro.m.jd.com/mall/active/3Rho97HkMaGFycLzAWfFdvZdyvRn/index.html) IT BOOK多得(或扫描京东二维码)查看详情吧!

82a2ef617505ea5f22ffc0f49b09e35d.png

4d47c3f61434ba397dd71139c1629530.png

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

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

相关文章

【前端 - CSS】第 10 课 - CSS 引入方式

欢迎来到博主 Apeiron 的博客,祝您旅程愉快 ! 时止则止,时行则行。动静不失其时,其道光明。 目录 1、缘起 2、CSS 引入方式 2.1、内部样式表 2.2、外部样式表 2.3、行内样式 3、总结 1、缘起 要想在 HTML 代码中写入 CSS 代…

English Learning - L3 作业打卡 Lesson5 Day33 2023.6.6 周二

English Learning - L3 作业打卡 Lesson5 Day33 2023.6.6 周二 引言🍉句1: And theres a student reading an English textbook.成分划分弱读连读语调 🍉句2: What do their choices say about them?成分划分连读爆破语调 🍉句3: Do you jud…

nodejs+vue+Express论坛网站34t91

本论坛网站有管理员,用户,普通管理员。管理员功能有个人中心,用户管理,普通管理员管理,论坛类别管理,交流论坛管理,系统管理等。用户功能有个人中心,交流论坛管理,我的收…

华为OD机试真题 JavaScript 实现【水仙花数】【2022Q4 100分】

一、题目描述 所谓水仙花数,是指一个n位的正整数,其各位数字的n次方和等于该数本身。 例如153是水仙花数,153是一个3位数,并且153 1^3 5^3 3^3。 二、输入描述 第一行输入一个整数n,表示一个n位的正整数。n在3到…

单容水箱建模(自衡单容水箱+无自衡单容水箱)

自衡单容水箱Simulink建模和PLC源代码请参看下面文章链接: 单容双容水箱建模(simulink仿真+PLC代码)_RXXW_Dor的博客-CSDN博客PLC通过伯努利方程近似计算水箱流量详细内容请参看下面的文章博客PLC通过伯努利方程近似计算水箱流量(FC)_怎么用伯努利方程求某水位流量_RXXW_Dor的…

基础汇编语言编程

目录 什么是汇编语言? 工程搭建 新建工程 环境设置 测试是否成功 正式学习汇编语言 数据处理指令 填充,加,减,乘 思考:我们可以看到R0寄存器可以存放8位十六进制数,那么0x12345678能不能用mov存入&am…

java SSM 摄影作品网站myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM 摄影作品网站系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,springspringMVCmybatis),对理解JSP java编程开发语言有帮助,系统具有完整的源代 码和数据库,系统主要采…

会用Python做副业的人,有多豪横!

前两天一个朋友找到我吐槽,说工资一发交完房租水电,啥也不剩,搞不懂朋友圈里那些天天吃喝玩乐的同龄人钱都是哪来的? 确实如此,刚毕业的大学生工资起薪都很低,在高消费、高租金的城市,别说存钱…

浏览器跨域请求

跨域是浏览器的一种同源策略,所以该概念只存在于通过浏览器访问服务里。 如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现 请求的url地址,必须与浏览器上的…

Vue3 ElementPlus Dialog封装 (二:使用provide inject)

引言 上一章Vue3 ElementPlus Dialog封装 (一:使用props emit) propemit实现的方法用于父子组件比较方便, 跨多层次组件比较麻烦 vue3 中 还提供了provide和inject方法供组件间通信(参考官网图片), 本篇使用该方法实现上章效果 实现原理 参考…

K8S之Ingress 对外暴露应用(十四)

• Ingress为弥补NodePort不足而生 • Pod与Ingress的关系 • Ingress Controller • Ingress 规则配置 一,Ingress为弥补NodePort不足而生 NodePort存在的不足: • 一个端口只能一个服务使用,端口需提前规划 • 只支持4层负载均衡二&#x…

九耶丨阁瑞钛伦特-大型计算机硬件组成(二)

TSO: TSO是Time Sharing Option的缩写,用户可以通过TSO命令和系统进行交互式工作。TSO命令直接使用并不方便,所以IBM又在TSO下开发了程序产品ISPF/PDF(Interactive System Productivity/Program Development Facility)其中ISPF支…

VAPS XT4.2 与 VS2013 安装

VAPS XT4.2 与 VS2013 安装 安装顺序 安装 VS2013安装 License tool安装 VAPS XT4.2VS2013 的安装 安装 VS2013,安装内容全选,安装路径选择D盘;VS2013 激活,网上找密钥,比如:【BWG7X-J98B3-W34RT-33B3R-JVYW9】;电脑重启;Win+R,sysdm.cpl,打开环境变量,查看VS相关的…

Linux SSH命令实战教程,提升你的服务器管理基本功!

前言 大家好,又见面了,我是沐风晓月,本文是专栏【linux基本功-基础命令实战】的第62篇文章。 专栏地址:[linux基本功-基础命令专栏] , 此专栏是沐风晓月对Linux常用命令的汇总,希望能够加深自己的印象&am…

java生成、识别条形码和二维码

一、概述 使用 zxing 开源库 Zxing主要是Google出品的,用于识别一维码和二维码的第三方库主要类:BitMatrix 位图矩阵MultiFormatWriter 位图编写器MatrixToImageWriter 写入图片 可以生成、识别条形码和二维码 内置三种尺寸:enum Size {SMALL, MIDDLE, …

【习题】习题 2 - 编写程序求当前机器的字节序

欢迎来到博主 Apeiron 的博客,祝您旅程愉快 ! 时止则止,时行则行。动静不失其时,其道光明。 目录 1、缘起 2、字节序影响 3、示例代码 4、总结 1、缘起 在计算机中,字节序(Byte Order)指定了…

一文带你彻底掌握Java 中的Stream流(详细)

本文目录 学习目标中间操作Filter(过滤)Map(转换)Sorted(排序)Distinct(去重)Limit(限制)Skip(跳过)Peek(展示) 终止操作forEach(循环)Collect(收集)Count(计数)Reduce(聚合)AnyMatch(任意匹配)AllMatch(全部匹配)NoneMatch(无匹配) 使用Stream流的优缺点:优点&…

投票活动小程序开发搭建

由于小程序是基于微信开发者工具编写的,因此我先介绍一下需要使用的工具和技术: - 微信开发者工具:用于开发、调试和发布小程序。 - 小程序云开发:用于存储数据和进行后端逻辑处理。 - uni-app框架:uni-app 是一个使…

组件更新的底层逻辑

第一种更新:组件更新的逻辑,当修改了相关状态,组件会更新 1.触发shouldComponentUpdate 周期函数:是否允许更新 shouldComponentUpdate(nextProps, nextState) { // nextState: 存储要修改的最新状态 // this. state:存储的还是修改前的状态…

分布式系统常见的数据分区算法

文章目录 顺序分区轮询分区算法时间片轮转分区算法数据块分区算法业务主题分区算法 哈希分区节点取模分区算法一致性哈希分区算法(重点)1.Hash环2.容错性和可扩展性3.数据倾斜4.带有限负载的一致性哈希算法5.带虚拟节点的一致性哈希算法 虚拟槽分区算法&…