Python学习 | 一个JAVA程序员学习另外一门面向对象的语言_父类

能阻止你成功的人,只有你自己

 

vlog

  • 时间:2020年03月06日-2020年03月07日 ——————一个晚上、半个白天
  • 学习方式:视频(黑马),流畅的Python,博客,百度
  • 完成内容:python面向对象和文件操作内容
  • 博客目的:总结归纳,当然要能帮助其他刚学习Python的童鞋,不胜荣幸
  • 人物:一个心血来潮学习Python的JAVA程序员

 

 

正文

面向对象

定义

  • 面向对象就是做一件事情之前,先找封装了这个功能的对象,而不是自己去写,我们写出来的功能也是一个一个的对象去供别的别像调用去完成特定的事
  • 相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法
  • 在完整某一个需求前,首先确定则这–要做的事情
  • 根据职责确定不同的对象,在对象内部封装不同的方法
  • 最后完成的代码,就是顺序的让不同的对象调用不同的方法
  • 面向对象比较适合复杂项目的开发

类和对象

  • 类是一群具有相同特征或者行为的事务的一个统称,是抽象的,不能直接使用
  • 特征被称为属性,行为被称为方法
  • 类就相当于造飞机的图纸,是一个模板,是负责创建对象的
  • 对象就是由类创建出来的一个具体存在,可以直接使用
  • 由哪一个类创建出的对象,就拥有哪一个类中定义的属性和方法,不同的对象属性可能不同
  • 对象就相当于用飞机图纸造出来的飞机
  • 在程序开发中,应该先有类,再有对象
  • 类的三要素
    • 类名这类事物的名字,满足大驼峰命名法
    • 属性:这类事物具有什么样的特征
    • 方法,这类事物具有什么样的行为
  • 在Python中对象几乎是无处不在的,变量、数据、函数都是对象,函数对象可以当做参数和返回值传递(函数对象是一等公民)
  • 使用内置函数dir传入标识符/数据,就可以查看对象内的所有属性和方法
类的内置方法
  • __方法名__格式是Python提供的内置方法、函数
    • new 方法,创建对象的时候会自动调用
    • init 方法,对象被初始化的时候,会自动调用
    • del 方法,对象在内存中被销毁之前会调用
    • str 方法,返回对象的描述信息,print函数输出会调用
类的定义
  • 在Python中定义一个只包含方法的类

    class 类名:
        def 函数名(self,参数列表):
            pass
    
  • 类中的方法,区别在于,第一个属性一定是self,而在函数中定义一个方法,第一个参数如果是self会被当成一个普通的参数,调用函数的时候需要传入

  • 类名要遵守大驼峰命名方法,和JAVA一样

  • 创建对象

    变量名 = 类名()
    tom = Cat()
    
引用
  • 指向对象的变量是一个引用
  • 变量中记录的是对象在内存中的地址
  • 使用print函数输出变量的时候,默认可以看见这个对象的类和16位的内存地址
  • print函数中数字的输出方式
    • %d以十进制输出数字
    • %x以十六进制输出数字
  • 两个对象的引用变量==可以判断内存中的地址,判断是不是同一个对象
  • 多个对象的属性互相不干扰
  • 一个对象的属性可以是另外一个对象
初始化方法
  • 当使用类名()创建对象的时候,会自动执行以下操作
    • 1.为对象在内存中分配空间–创建对象
    • 2.为对象的属性设置初始值,初始化方法__init__,这个方法就是python中专门定义属性的方法
给类中添加属性
  • 直接对象的引用.属性名 = 属性值(在类的外部)

    • 这么操作十分简单,但是不建议这么操作(因为对象的属性应该封装在类的内部,如果在方法内部使用属性的时候,外部没有指定变量会报错,没有此属性)
  • 类中方法的self属性指的是调用和这个方法的对象,相当于JAVA中的this

  • 如果在方法中使用self.属性名来获取属性的时候,属性不存在会报错,没有此属性

  • 使用初始化方法定义属性,在__init__方法内部使用

    self.属性名 = 属性值
    def __init__(self):
        self.name = "YKZ"
    
  • 多参数初始化方法

    class 类名:
        def __init__(self,参数列表):
            初始化...
    
__del__方法
  • 一个对象从内存中被销毁之前最后会调用了一下__del__方法,如果对象死之前你想再让他干点什么事,就可以使用此方法
  • del关键字会销毁变量,使用del 对象引用名就可以触发调用此方法
__str__方法
  • 默认print(对象的引用)会输出对象的类名和对象的内存地址
  • 实现__str__方法之后会输出这个方法里面的内容,但是要记得要把输出的内容return回去,并且必须返回字符串,返回其他的类型会报错
身份运算符
  • 用于比较两个对象的内存地址是否一致,是否是同一个对象的引用

  • x is y 相当于id(x) == id(y),x is not y 相当于id(x) != id(y)

  • 在Python中针对None的比较时,建议使用is判断

  • == 一般用来比较变量的值

    list1 = [1,2,3]
    list2 = [1,2,3]
    list1 == list2 True
    list1 is list2 False
    
私有属性和方法
  • Python中定义私有属性和方法只需要在属性和方法前面加两个下划线
    这样类外面就访问不到私有属性和方法了

  • 是伪私有属性和方法,调用的时候只需要加上_类名即可调用到,但是不要这么做

    class Cat:
        def __init__(self):
            self.__age = 18
    
        def __eat(self):
            print("%d岁的猫吃东西" % self.__age)
    
    
    cat = Cat()
    # cat.__eat 报错
    # cat.__age 报错
    print(cat._Cat__age)
    cat._Cat__eat()
    

继承

作用
  • 继承的主要作用就是代码的重用;
  • 子类拥有父类的所有属性和方法
  • 继承具有传递性;
    子类拥有父类以及父类的父类中封装的所有属性和方法
  • 子类不能在自己类的内部直接访问父类中的私有属性和私有方法,但是可以在父类的共有类中间接访问
定义
class 类名(父类名):
    pass
方法的重写
  • 当父类的方法不能满足子类的需要,就可以对方法进行重写;
    在子类中定义一个一样方法名的方法即可重写

  • 如果重写的时候与父类的参数列表不一样的话,解释器会警告,运行不会报错

  • 如果需要对父类的方法进行拓展,可以使用super().父类方法名(),最常用的就是在对父类方法进行重写的时候,对父类的方法进行调用;
    子类有属性的话,可以在构造方法中给父类的属性也赋值:

    def __init__(self, name):
        super().__init__(name)
        self.__age = 18
    
  • 只有重写了需要使用super()调用,否则直接self调用即可

  • Python2.*中可以使用父类名.方法名(self)来调用父类中的方法,Python3中不推荐使用(不指定self会报错)

  • super()不能直接访问父类的属性,会报错

多继承
  • Python中是有多继承的

  • 子类可以继承多个父类,并且拥有所有父类的属性和方法

    class 子类名(父类名1,父类名2...):
        pass
    
  • 如果父类中存在同名的方法或者属性,那么我们使用多继承就要小心了,尽量避免使用多继承

  • MRO(方法搜索顺序)

    • 类中内置了一个__mro__属性可以查看方法搜索顺序;
      在搜索这个方法的时候是按照这个输出结果从左向右查找的,没有找到就找下一个类,找到就不再找了,都找不到就报错了
  • 新式类和旧式类

    • python3.*中所有的类都默认继承了object类,python2.*中没有;为了能更好的兼容python2.*我们写类的时候如果没有任何继承,最好

      类名(object):
          pass
      
  • 多态

    • 多态基于继承和重写方法
    • 不同的子类对象调用相同的父类方法,产生不同的执行效果

类属性

  • 每一个对象都有自己独立的内存空间,保存各自不同的属性
    多个对象的方法,在内存中只有一份,在调用方法的时候,需要把对象的引用传递到方法的内部

  • 在Python中类也属于一个对象;
    在程序运行的时候,类同样会被加载到内存中;
    在程序运行时,类对象在内存中只有一份,使用一个类可以建造出很多个对象实例;
    类对象可以有自己的属性和方法;

    定义:
    class 类名(object):
        变量名 = 值
        def __init__(self):
            pass
    
  • 调用使用类名.属性名来调用,还可以使用对象.属性名来调用类属性(python中对象调用属性会先在对象内部查找,找不到就回去类属性里面找),不建议使用对象查找类属性,因为容易产生混淆

  • 对象.类属性 = 属性值并不会给类属性赋值,而是会在对象里面新建一个属性

类方法

  • 定义:

    @classmethod
    def 类方法名(cls):
        pass
    
  • 通过类名.来调用类方法时,不需要传入cls参数

  • 在内方法内部,可以通过cls来调用类属性,也就可以使用cls去调用其他的类方法

静态方法

  • 如果需要在类中封装一个方法
    这个方法既不需要访问实例属性或者调用实例方法
    也不需要访问类属性或者类方法,我们就可以定义成一个静态方法

  • 定义

    @staticmethod
    def 静态方法名():
        pass
    
  • 也是通过类名来访问

单例设计模式

  • __new__方法;
    为对象分配内存空间
    返回对象的引用;

  • 引用必须返回,每次创建对象都会在走__init__方法,所以可以设置一个类变量,初始化一次之后就不再初始化了

  • 代码

    class MusicPlayer(object):
        # 记录第一个被创建对象的引用
        instance = None
        # 记录是否执行过初始化动作
        init_flag = False
    
        def __new__(cls, *args, **kwargs):
    
            # 1. 判断类属性是否是空对象
            if cls.instance is None:
                # 2. 调用父类的方法,为第一个对象分配空间
                cls.instance = super().__new__(cls)
    
            # 3. 返回类属性保存的对象引用
            return cls.instance
    
        def __init__(self):
    
            if not MusicPlayer.init_flag:
                print("初始化音乐播放器")
    
                MusicPlayer.init_flag = True
    

异常

  • Python解释器遇到一个错误,会停止程序的运行,并且提示一些错误信息,这就是异常;程序停止并且提示错误信息这个动作,我们通常称之为抛出异常;
    程序开发时,很难将所有特殊的情况处理的面面俱到,通过异常捕获可以针对突发事件集中的处理,从而保证程序的稳定性和健壮性;

  • 格式

    try:
        尝试执行的代码
    except 错误类型1:
         出现错误的处理
    except 错误类型2,错误类型3:
         出现错误的处理
    except Exception as result:
         print("未知错误s%" % result)
    else:
        print("没有异常才会执行的代码")
    finally:
        print("有没有异常都会执行的代码")
    
  • 异常的传递
    当函数/方法执行出现异常的时候,会将异常传递给函数/方法的调用一方;
    如果传递到主程序,仍然没有处理异常,程序才会终止

  • 主动的抛出异常
    先定义一个Exception异常对象,然后使用raise关键字抛出

    ex = Exception("长度不足8位")
    raise ex
    

模块

  • 每一个以py结尾的Python源码文件都是一个模块;
    模块的名称和变量的命名一样(数字、字母、下划线,不能以数字开头);
    在模块中定义的全局变量、函数、类都是提供给外界直接使用的工具;
    模块就好比是工具包,如果你想使用这个工具包,就需要先导入这个模块

  • 模块的导入

    模块的导入
    import 模块1,模块2 (PEP8不推荐使用)
    每个导入的模块独占一行(推荐)
    import 模块1
    import 模块2
    
  • 导入之后可以使用模块名.来使用模块中提供的全局变量、函数和类

  • 给模块起别名,这样就可以使用别名来调用模块中的内容,模块的别摸应该符合大驼峰命名
    import 模块名 as 别名(满足大驼峰

  • 部分导入
    from 模块1 import 工具名
    知道如一个工具,而且不需要通过模块名点来调用(全局变量、类和函数均可导入,但是本类中有定义的同名的会把导入的覆盖掉,导入的有同名的会以后倒入的为准
    如果有重名的可以起别名区分

    from 模块名 import *
    不推荐使用,命名重复不会有提示

  • 系统导入模块的时候会先查看当前的文件目录,有的话直接导入,没有的话,在系统目录寻找,所以模块名不要和系统文件重名,模块都有一个内置属性__file__来查看当前模块的路径
    random模块的系统路径是D:\Python38\lib\random.py

  • name

    • 一个模块被导入的时候,这个模块里面所有可执行的代码都会被执行,可以想象这个模块是被运行了一遍;
      __name__就是在本模块执行的时候是__main__而别的模块执行的时候就是模块名
      我们不希望别人导入执行的代码可以写在一个if语句里面

      if __name__ == "__main__":
          while True:
              print("1111111======")
      

  • 包是一个包含多个模块的特殊目录

  • 目录下有一个特殊的文件__init__.py

  • 要在外界使用包中的模块,需要在__init__.py中指定对外界提供的模块列表

    from . import send_message
    from . import receive_message
    

文件

概念

  • 计算机的文件,就是储存在某种长期存储设备上的一段数据;
    长期存储的设备包括:硬盘、U盘、移动硬盘、光盘…

存储方式

  • 二进制文件
    只能使用特定的软件查看的文件,如图片和视频

  • 文本文件,其实也是二进制文件,但是可以使用文本编辑器打开

文件的操作

  • 套路

    • 打开文件;
      读写文件中的内容;
      关闭文件;
  • 方法

    • open 打开文件(函数)
    • read 将文件的内容读取到内存(方法)、read方法会一次性把所有的数据加载到内存,文件过大会对内存造成很大影响,readline方法,每次读取一行
    • write 将制定的内容写入文件(方法)
    • close 关闭文件(方法)
      如果忘记关闭文件,会造成系统资源的损耗,而且会影响对后续资源的访问;
  • 打开文件的方式(open函数的第二个参数)

    • r,以只读的方式打开,如果文件不存在会报错
    • w,以只写的方式打开文件,文件存在会被覆盖,不存在会创建文件
    • a,以追加的方式打开文件,如果文件已经存在,文件指针会放到文件的末尾,如果文件不存在会创建新文件写入
    • r+,以读写的方式打开文件,文件的指针会放到文件的开头,如果文件不存在,抛出异常
    • w+,以读写的方式打开文件,如果文件存在会被覆盖,如果文件不存在会创建新文件
    • a+,以读写的方式打开文件,如果文件已经存在,文件的指针会在文件的末尾。文件不存在会创建新文件写入;
    • rb 以二进制的方式打开文件
    • wb以二进制的方式写入文件
  • 编码

    • Python2.*的解释器默认使用ASCII编码
    • Python3.*的计时器默认使用的是UTF-8的编码

eval函数

  • 将字符串当成有效表达式来执行并返回结果
  • 不要乱用eval函数来接受用户传过来的字符串
    import(“os”).system(“ls”)会执行列出当前的目录和文件,要是删除文件呢?

Python学习 | 一个JAVA程序员学习另外一门面向对象的语言_类属性_02


Python学习 | 一个JAVA程序员学习另外一门面向对象的语言_编程语言_03
喜欢的朋友可以加我的个人微信,我们一起进步