• 写给小白的Python之016:面向对象-魔法方法


    导读:

    1. __init__方法

    2. __str__、__repr__方法

    3. __del__方法

    4. __new__方法

     

    魔法方法:在恰当的时候会自动执行的方法。

    • 魔法方法名两边各有2个下划线。
    • 方法名称都已经由官方规定好了的。

    1. __init__方法

    在创建实例时,通常可能都需要有特定的初始状态,所以一个类可以定义一个名为 __init__() 的特殊方法(构造函数):

    def __init__(self):

        self.data = []

    __init__()在创建对象(类的实例化)之后自动执行。用于初始化对象的属性。

    过程:定义类->创建对象->执行__init__方法->赋值给对象名。

    __init__不能显式地return一个值,因为它默认返回None。

     

    在类的方法里定义属性的固定值,则每个对象实例变量的属性值都是相同的。__init__方法能让实例化的每个对象,都有不同的属性值。

    在__init__(self)中定义好形参,实例化对象时,传入实参。

    def __init__(self, name, skill):

            """ __init__() 方法,用来做变量初始化 或 赋值 操作"""

            self.name = name

            self.skill = skill

    一个类中的多个对象,每个对象的属性是各自保存的,都有各自独立的地址;

    但是实例方法是所有对象共享的,只占用一份内存空间。类会通过self来判断是哪个对象调用了实例方法

    2. __str__、__repr__方法

    __str__方法

    __str__()在打印对象时自动执行。用于返回一个字符串,作为对象的描述信息。

    该方法只有self一个参数,必须要有返回值,且返回值必须为字符串类型,当在类的外包部print(对象)则打印这个返回值。如果没有__str__(),则默认打印 对象在内存的地址。

    class Student(object):
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return "%s 是最帅的!" % self.name
    
    
    print(Student('salmond'))  # 输出__str__方法返回的内容
    Student('salmond')  # 输出内存地址

    __repr__方法

    __str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说, __repr__()是为调试服务的。

    Student('salmond')  输出的是内存地址,如何让它显示内容呢?解决办法是再定义一个__repr__()。但是通常__str__()和__repr__()代码都是一样的,所以,有个偷懒的写法:

    class Student(object):
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return 'Student object (name=%s)' % self.name
    
        __repr__ = __str__
    
    
    s = Student('salmond')
    print(s)

    3. __del__方法

    当对象被销毁时,自动调用。用于验证对象是否被销毁、释放资源(关闭文件)等。

    class Hero(object):
    
        def __init__(self, name):
            print('__init__方法被调用')
            self.name = name
    
        def __del__(self):
            print("__del__方法被调用")
            print("%s 被 GM 干掉了..." % self.name)
    
    
    taidamier = Hero("泰达米尔")  # 创建对象
    print("%d 被删除1次" % id(taidamier))
    del(taidamier)  # 删除对象
    
    print("--" * 10)
    
    gailun = Hero("盖伦")  # 内存地址
    gailun1 = gailun  # 内存地址同上
    gailun2 = gailun  # 内存地址同上
    
    print("%d 被删除1次" % id(gailun))
    del(gailun)
    print("%d 被删除1次" % id(gailun1))
    del(gailun1)
    print("%d 被删除1次" % id(gailun2))
    del(gailun2)  # 当引用计数为0时,才会调用__del__方法

    总结:

    1. 当有变量保存了一个对象的引用时,此对象的引用计数就会加1;

    2. 当使用del() 删除变量指向的对象时,则会减少对象的引用计数。如果对象的引用计数不为1,那么会让这个对象的引用计数减1,当对象的引用计数为0的时候,则对象才会被真正删除(内存被回收)。

    4.__new__方法

     当我们创建一个类的实例时,类会先调用 __new__(cls[, ...]) 来创建实例,然后__init__ 方法再对该实例(self)进行初始化。

     一般情况下,我们不需要重载 __new__ 方法。但在某些情况下,我们想控制实例的创建过程,这时可以通过重载 __new_ 方法来实现。

    # __new__和__init__的作用,重载 __new__ 方法
    class A(object):
    
        def __init__(self):
            print(self)  # <__main__.A object at 0x000001DB1C0B7828>
            print("这是 init 方法")  # 这是 init 方法
    
        def __new__(cls):
            print(id(cls))  # 2040549602280
            print("这是 new 方法")  # 这是 new 方法
            ret = object.__new__(cls)
            print(ret)  # <__main__.A object at 0x000001DB1C0B7828>
            return ret
    
    
    print(id(A))  # 2040549602280
    A()

    总结:

    • _ 重载 __new__ 方法,需要返回类的实例;因此,__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供。
    • _ __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例。
    • _ __init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。
    • _ 我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节。
    • _  __new__ 是在 __init__ 之前被调用的;
    • _  __new__ 是类方法, __init__ 是实例方法;

    重载__new__示例:

    class A(object):
        __dict = dict()
    
        def __new__(cls):
            if 'key' in A.__dict:
                print('EXISTS')
                return A.__dict['key']
            else:
                print('NEW')
                return object.__new__(cls)
    
        def __init__(self):
            print('INIT')
            A.__dict['key'] = self
    
    
    >>> a1 = A( )
    NEW
    INIT
    
    >>> a2 = A( )
    EXISTS
    INIT
    
    >>> a3 = A( )
    EXISTS
    INIT
  • 相关阅读:
    redis 误删dump.rdb 解决方案
    Redis 初级应用
    .net core 依赖注入
    Android 基础总结
    hander用法笔记
    百万条数据快速查询优化技巧参考(优化并不是绝对,具体得根据业务实际情况)
    网站收藏
    自定义MVC HtmlHelpe之分页
    asp.net 页面请求原理
    Two Sum
  • 原文地址:https://www.cnblogs.com/salmond/p/9000351.html
Copyright © 2020-2023  润新知