• Python的self作用,以及__init__,__new__


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

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

    先看个例子:

    1. class Example:
    2.     def animal(self):
    3.         self.dog = "大黄"
    4.     def Dog(self):
    5.         print(self.dog)
    6. if __name__ == "__main__":
    7.     example = Example()
    8.     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__中

    1. class Example:
    2.     def __init__(self) -> None:
    3.         self.dog = "大黄"
    4.     def Dog(self):
    5.         print(self.dog)
    6. if __name__ == "__main__":
    7.     example = Example()
    8.     example.Dog()

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

    1. class Example:
    2.     def __init__(self, dog) -> None:
    3.         self.dog = dog
    4.         
    5.     def Dog(self):
    6.         print(self.dog)
    7. if __name__ == "__main__":
    8.     example = Example("大黄")
    9.     example.Dog()

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

    def __init__(self, dog)

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

    动态加载

    1. class Example:
    2.     def set_name(self, dog):
    3.         self.dog = dog
    4.         
    5.     def Dog(self):
    6.         print(self.dog)
    7. if __name__ == "__main__":
    8.     example = Example()
    9.     example.set_name("大黄")
    10.     example.Dog()

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

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

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

    这里提到了__new__。


    再来看看实例对象。

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

    1. class Person:
    2.     def __init__(self, name):
    3.         self.name = name
    4.     def say_hello(self):
    5.         print(f"Hello, my name is {self.name}.")
    6. person = Person('清安')
    7. # 相当于Person.say_hello(person)
    8. person.say_hello()

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

    所以

    1. class Person:
    2.     def __init__(self, name, age=18):
    3.         print('__init__ id is ',id(self))
    4.         self.name = name
    5.         self.age = age
    6.     def show(self):  # self永远指向当前实例自身,this
    7.         print(f"show id is {id(self)}")
    8.         print(f"{self.name} is {self.age} yeas old!")
    9. pe = Person('拾贰'20)  # 实例化
    10. pe.show()   # 相当于show(pe)  解释器会把pe赋值给self
    11. 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,您可以在类的方法中访问和操作实例对象的属性和方法。

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

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

    再来看看__new__

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

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

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

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

    1. class Example:
    2.     def __new__(cls):
    3.         instance = super().__new__(cls)
    4.         instance.name = "清安"  # 手动创建实例属性name
    5.         return instance
    6.     def print_name(self):
    7.         print(f"Name: {self.name}")
    8. example = Example()
    9. 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。

    1. class Example:
    2.     def __new__(cls):
    3.         instance = super().__new__(cls)
    4.         instance.name = "清安"  # 手动创建实例属性name
    5.         return instance
    6.     def print_name(self):
    7.         print(f"Name: {self.name}")
    8.     # def print_age(self):
    9.     #     print(f"Age: {self.age}")  # 尝试访问未定义的属性age
    10. example = Example()
    11. example.print_name()
    12. example.print_age()   # 报错:AttributeError: 'Example' object has no attribute 'age'

    __new__与__init__区别

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


    个题外话的例子

    1. class ClassA:
    2.     def __new__(cls):
    3.         instance_b = ClassB()  # 在__new__方法中创建ClassB的实例
    4.         instance_a = super().__new__(cls)
    5.         instance_a.class_b = instance_b  # 将ClassB的实例赋值给当前类的属性
    6.         return instance_a
    7.     def __init__(self):
    8.         pass
    9. class ClassB:
    10.     def __init__(self):
    11.         self.name = "B"
    12.     def __str__(self):
    13.         return self.name
    14. obj_a = ClassA()
    15. print(obj_a.class_b)  # 输出:B

    此处没啥说的

    1. class Example:
    2.     def __init__(self,age=0) -> None:
    3.         self.age = age
    4.     
    5.     def print_name(self):
    6.         self.age += 1
    7.         return self
    8. example = Example().print_name()
    9. 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

  • 相关阅读:
    短视频矩阵系统seo源码saas开发---一手源头
    springboot整合mybatis实现增删改查
    3:kotlin 逻辑控制(Control flow)
    【图像分类】【深度学习】【Pytorch版本】VggNet模型算法详解
    第一章 网络基础知识
    Leetcode1-两数之和详解
    Android Studio 项目引入ProtoBuf(附序列化与反序列化)
    绘制矩阵散点图
    设计模式——工厂模式详解(代码演示)
    Android 图片上传
  • 原文地址:https://blog.csdn.net/weixin_52040868/article/details/131137345