zoukankan      html  css  js  c++  java
  • 第041讲:魔法方法:构造和析构

    #搬运自FishC论坛,该系列已完结,共有00~96节,本人学习过程中的记录等。

    #FishC论坛:http://bbs.fishc.com/forum.php

    #小甲鱼课程规划帖:http://bbs.fishc.com/thread-1053-1-1.html 此教程适合完全零基础的朋友学习,

    课堂笔记

    -魔法方法总是被双下划线包围,例如:__init__

    -魔法方法是面向对象的Python的一切,如果你不知道魔法方法,说明你还没意识到面向对象的Python的强大。(不是平时写的Python脚本)

    -魔法方法的“魔力”体现在他们总能在适当的时候被自动调用

    __init__(self,[, ...])

    这个就是其他语言的构造的方法 。也就是类在实例化对象的时候,首先会调用的一个方法。

    需求!举个例子,假设我们现在要定义一个矩形类,在 定义的时候我们需要它有长和宽,长和宽这2个参数就在实例化的时候传入2个参数;在实例化的时候它会调用这个__init__方法,所以我们在这里才需要对__init__方法进行重写,因为默认它是没有参数的,需要传入两个参数,这就叫做“需求”。self.x是类实例化之后的实例对象的一个局部变量,而右边的x是传入的参数x。self代表类的实例,而非类

    >>> class Rectangle:
        def __init__(self, x, y):
            self.x = x
            self.y = y
        def getPeri(self):
            return (self.x + self.y) * 2
        def getArea(self):
            return self.x * self.y
    
        
    >>> rect = Rectangle(3, 4)
    >>> rect.getPeri()
    14
    >>> rect.getArea()
    12
    >>> 

    这里主要,__init__的返回值一定是返回一个 None,

    >>> class A:
        def __init__(self):
            return "A for A.Cup"
    
        
    >>> a = A()
    Traceback (most recent call last):
      File "<pyshell#4>", line 1, in <module>
        a = A()
    TypeError: __init__() should return None, not 'str'
    >>> 

    其实__init__()并不是实例化对象时第一个被调用的魔法方法。第一个被调用的应该是这个__new__(cls[, ...])。它跟其它的魔法方法不同,第一个参数不是self,而是class,也就是这个类在__init__()之前被调用,如果后面有参数,那后边的参数会原封不动地传给这个__init__()方法。(new在内存给对象开盘存储空间地址,init初始化对象属性,str直接调用对象返回内容)

    那new方法需要一个示例对象作为返回值,它需要返回一个对象。通常是返回cls 这个类的示例对象。(new方法只接受 cls 作为它的第一个参数,__init__一个参数是self,因为调用__new__之前连示例都还没有,因此那时根本没有self的存在)

    python3中类的重点与难点:__new__方法与__init__方法,来自链接:https://blog.csdn.net/qq_41020281/article/details/79638370

    通俗的讲解Python中的__new__()方法,来自,原文出处链接:https://blog.csdn.net/sj2050/article/details/81172022

    >>> class CapStr(str):
        def __new__(cls, string):
            string = string.upper()
            return str.__new__(cls, string)
    
        
    >>> a = CapStr("I love FishC.com!")
    >>> a
    'I LOVE FISHC.COM!'
    
    #解释:我们这个CapStr类是继承于str这个类的,而这个str类是一个不可改变的类型,(字符串是一个不可改变的类型),我们就不能用__init__()对它自身进行修改,所以我们要做new的时候把它进行一个替换(string = string.upper()),然后将替换后的调用这个str.__new__()
    return str.__new__(cls, string)  #返回的是一个新的str类,还要new一次把它赋值给原来的类。不写的话会调用它基类的那个new
    
    
    #理一下:首先,先声明一个类叫做CapStr,在里面重写魔法方法__new__(),然后在__new__()方法中将传入的string变成大写,然后将变成大写的string交给str类中的__new__方法处理,生成一个字符串
    class A:
        pass
    
    >>> class B(A):
        def __new__(cls):
            print("__new__方法被执行")
            return super().__new__(cls)
        def __init__(self):
            print("__init__方法被执行")
    
            
    >>> b = B()
    __new__方法被执行
    __init__方法被执行
    >>> 

    __del__(self)

    析构器,当对象将要被销毁时,这个方法就会自动的被调用,但一定要注意的是,并非说是。这个方法是当垃圾回收机制的时候,这时候才会调用这个对象的del方法。并不是发生del就会触发del方法,当这个对象生成后,所有对它的引用都被删除后,才会启动这个垃圾回收机制,销毁对象时就会调用__del__()方法。

    >>> class  C:
        def __init__(self):
            print('我是__init__方法,我被调用了。。。')
        def __del__(self):
            print('我是__del__方法,我被调用了。。。')
    
            
    >>> c1 = C()
    我是__init__方法,我被调用了。。。
    >>> c2 = c1
    >>> c3 = c2
    >>> del c3
    >>> del c2
    >>> del c1
    我是__del__方法,我被调用了。。。
    >>> 

    课后习题

    测试题:

    0. 是哪个特征让我们一眼就能认出这货是魔法方法?

    前后有两个下划线包围的时候,就是魔法方法。

    答:魔法方法总是被双下划线包围,例如 __init__

    1. 类实例化对象所调用的第一个方法是什么?

    __new__()这个方法。

    答:__new__ 是在一个对象实例化的时候所调用的第一个方法。它跟其他魔法方法不同,它的第一个参数不是 self 而是这个类(cls),而其他的参数会直接传递给 __init__ 方法的。

    2. 什么时候我们需要在类中明确写出 __init__ 方法?

    当我们有“需求”的时候,就是我们需要初始化一些参数、函数时。

    答:当我们的实例对象需要有明确的初始化步骤的时候,你可以在 __init__ 方法中部署初始化的代码。例子:

    # 我们定义一个矩形类,需要长和宽两个参数,拥有计算周长和面积两个方法。
    # 我们需要对象在初始化的时候拥有“长”和“宽”两个参数,因此我们需要重写__init__方法
    # 因为我们说过,__init__方法是类在实例化成对象的时候首先会调用的一个方法,大家可以理解吗?
    
    class Rectangle:
            def __init__(self, x, y):
                    self.x = x
                    self.y = y
            def getPeri(self):
                    return (self.x + self.y) * 2
            def getArea(self):
                    return self.x * self.y
    
    >>> rect = Rectangle(3, 4)
    >>> rect.getPeri()
    14
    >>> rect.getArea()
    12

    3. 请问下边代码存在什么问题?

    class Test:
            def __init__(self, x, y):
                    return x + y

    __init__()这个方法是不需要返回值的,这里 报typeerror吧

    答:编程中需要注意到 __init__ 方法的返回值一定是None,不能是其它!

    4. 请问 __new__ 方法是负责什么任务?

    复制给init建立一些需要的参数、方法;或者说是修改类的方法,new是负责买材料、零部件的,init负责制造东西

    答:__new__ 方法主要任务时返回一个实例对象,通常是参数 cls 这个类的实例化对象,当然你也可以返回其他对象。R

     

    5. __del__ 魔法方法什么时候会被自动调用?

    当回收机制启动的时候,要销毁一个变量时候,这个类的del方法就会自动调用。

    答:如果说 __init__ 和 __new__ 方法是对象的构造器的话,那么 Python 也提供了一个析构器,叫做 __del__ 方法。当对象将要被销毁的时候,这个方法就会被调用。"9Dx}XV
    ^+2 ,{Z
    但一定要注意的是,并非 del x 就相当于自动调用 x.__del__(),__del__ 方法是当垃圾回收机制回收这个对象的时候调用的。

    动动手

    0. 小李做事常常丢三落四的,写代码也一样,常常打开了文件又忘记关闭。你能不能写一个 FileObject 类,给文件对象进行包装,从而确认在删除对象时文件能自动关闭?

    要用到del方法吗,还是说new一个新的类方法。

    答:只要灵活搭配 __init__ 和 __del__ 魔法方法,即可做到收放自如。

    class FileObject:
        '''给文件对象进行包装从而确认在删除时文件流关闭'''
    
        def __init__(self, filename='sample.txt'):
            #读写模式打开一个文件
            self.new_file = open(filename, 'r+')
    
        def __del__(self):
            self.new_file.close()
            del self.new_file

    1. 按照以下要求,定义一个类实现摄氏度到华氏度的转换(转换公式:华氏度 = 摄氏度*1.8+32)

    要求:我们希望这个类尽量简练地实现功能,如下:

    >>> print(C2F(32))
    89.6

    答:为了尽量简练地实现功能,我们采取了“偷龙转凤”的小技巧。在类进行初始化之前,通过“掉包” arg 参数,让实例对象直接返回计算后的结果。

    class C2F(float):
            "摄氏度转换为华氏度"
            def __new__(cls, arg=0.0):
                    return float.__new__(cls, arg * 1.8 + 32)

    2. 定义一个类继承于 int 类型,并实现一个特殊功能:当传入的参数是字符串的时候,返回该字符串中所有字符的 ASCII 码的和(使用 ord() 获得一个字符的 ASCII 码值)。

    实现如下:

    >>> print(Nint(123))
    123
    >>> print(Nint(1.5))
    1
    >>> print(Nint('A'))
    65
    >>> print(Nint('FishC'))
    461
    # 当传入的参数是字符串的时候,返回该字符串中所有字符的 ASCII 码的和(使用 ord() 获得一个字符的 ASCII 码值)。
    
    class Nint(int):
        def __new__(cls, arg = 0):
            if isinstance(arg, str):
                total = 0
                for each in arg:
                    total += ord(each)
                arg = total
            return int.__new__(cls, arg)

    作者:Agiroy_70

    本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。

    博主的文章主要是记录一些学习笔记、作业等。文章来源也已表明,由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。

    博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!

  • 相关阅读:
    crontab 实际的应用
    php 求素数的二种方法
    linux svn配置hooks
    php执行超时(nginx,linux环境)
    php使用strpos,strstr,strchr注意啦,若是数字查找则会当成ASCII码处理
    php 处理大文件方法 SplFileObject
    高德地图定位
    jquery 实现鼠标点击div盒子移动功能
    centos 安装php缓存 apc或zend-opcode
    phpQuery用法总结
  • 原文地址:https://www.cnblogs.com/hale547/p/13368337.html
Copyright © 2011-2022 走看看