Python语言

Python 语言

来源:python语言基础
文档:python官方文档
平台:华为云

Tips

  • 1.一般三个字节表示一个中文字符;
  • 2.通过切片获取元素时,会包括起始位置的元素,不会包括结束位置的元素。
    做切片操作时,总会返回一个新的列表,不会影响原来的列表。切片的索引也是从0开始的。
  • ord() 函数返回的是其ASCII码值
  • join() 将序列中的元素以指定的字符连接生成一个新的字符串:str.join(sequence)
     wstr = "-"
     seq = ("a", "b", "c")
     print(wstr.join(seq))    # wstr为 a-b-c
  • Python中提供了6种内置的数据类型:数值Number、字符串String、列表List、元祖Tuple、字典Dictionary、集合Set。
  • Python中的复数由实数部分和虚数部分组成,二者都是浮点数;虚数不能单独存在,它们总是和一值为0.0的实数部分一起构成一个复数。复数对应的运算模块是cmath模块;
  • Python中常见的内置函数有:求绝对值abs(x);四舍五入round(x); 返回两个数值的商和余数:divmod(y,x); 如果是不同的类型的数字(int,float)进行计算,则结果类型为精度较高的那个类型。
  • Python中的字符串也是有序且不可变的。
  • 元组是一个有序且不可变的序列,其中的元素可以是任意对象。元组的存储可以让数据更安全。元组中只有一个元素时,需要在元素后面加上[ , ],告诉解释器这不是运算符号中的括号。两个元组可以通过 + 拼接。
  • 列表与数组:Python中列表和数组在形式上有点类似,但是本质不一样。Python中的内置数据结构中并没有数组,需要借助工具numpy实现。
  • 集合有逻辑运算:交集:set1 & set2两个集合中相同的元素;对称差集:set1 ^ set2两个集合中不同的元素; 并集:set1 | set2两个集合内总共的元素(重复的删除); 差集:set1 - set2集合①中包含而集二②不包含的元素;
  • 在Python中函数如果不使用return,不代表没有返回值,而是返回None;返回值不是必须的,可以没有返回值(即返回none);多个返回值时实际上返回值的是元组,如return a, b, c
  • pop是有返回值的,而remove是没有返回值的;
  • 定义函数def下面的注释“” 内容 “”,在下面加上help(函数名)之后,可以使用help(函数名)查看注释内容。
  • strip函数的作用是去空格,把str前面后面的空格都去掉;
  • Python区分代码块的空格是没有限制的,可以4个(常用),也可以是3个。
  • Python定义字符串是可以采用单引号和双引号(没有区别),也可以使用三引号(支持换行)。

7 文件操作

文件打开

  • open(file, mode=‘r’, buffering=-1, encoding_=None, errors=None, newline=None, closefd=True, opener=None)
    使用 open打开一个文件

    • 参数:file 表示要打开的文件的名字(路径)
    • 返回值:返回一个对象,这个对象就代表了当前打开的文件
  • 在windows系统下使用路径时,可以使用 /来代替 \,或者使用 \ 来代替 \,或者在原始字符串前面 +r 。

  • 如果目标文件距离当前文件比较远,则此时可以使用绝对路径(从磁盘的根目录开始写)如:
    file_name = r’D:\CODE\PycharmProjects\Python\test.txt’ file_obj = open(file_name) #打开file_name对应的文件

文件读取

  • 方法1:调用open()来打开一个文件,可以将文件分为两种类型。open()默认的是以文本文件形式打开的:

    • 1)纯文本文件(使用utf-8等编码编写的文本文件)
    • 2)二进制文件(图片,mp3, ppt等这些文件)
  • 如果需要读取中文,需要指定编码格式: with open(file_name, encoding=‘utf-8’) as file_obj:

  • 如果是直接调用 read()来读取文件中的内容时,会将文本文件的所有内容全部都读取出来,read()可以接受一个参数size,
    该参数用来指定要读取的字符的数量: content=file_obj.read(6)

    • 每一次读取都是从上次读取的位置开始读取的;
    • 如果剩下的字符数量小于 size, 则会读取剩下所有的
    • 如果已经读取到了文件的最后,则会返回 ‘’ 空串
  • 如果待读取的文件很大时,会一次性将文件的内容加载到内容中,容易导致内存泄漏;所以可以用size指定大小;

  • 如果读取的是大文件:可以创建一个循环来读取文件,每次读取指定大小size的文件内容,示例如下:

        with open(file_name,encoding='utf-8') as file_obj:
              file_content = ''   #定义一个变量来保存文件内容
              chunk = 100         #指定每次读取文件的大小
              while True:
                content = file_obj.read(size = chunk)   #每次读取chunk大小的文件
                if not content:   #检查是否读取到了内容
                  break           #读取完毕,退出循环
                file_content += content  #每次读取的内容拼接到一起
    
  • 方法2:

  • readline() 每次只读取一行

  • readlines() 每次读取一行将读取到的内容封装到一个列表中返回

        with open(file_name,encoding='utf-8') as file_obj:
              #r = file_obj.readlines()
              #pprint.pprint(r[0])
              #pprint.pprint(r[1])
              for t in file_obj:
                  print(t)
    

文件写入

使用open() 打开文件时必须要指定打开文件所要做的操作(读,写,追加),如果不指定操作类型,则默认为 只读文件。

  • 其他类型的操作:

    • r: 只读

    • w 可写,若文件不存在则创建文件,如果文件存在则会删除原文件内容,重新写入

    • a 追加内容,如果文件不存在则会创建文件,如果文件存在则会向文件中追加内容

    • x 用来新建文件,如果文件不存在则创建,存在则报错

    • + 为操作符增加功能 r+ 既可读又可写,文件不存在则报错 w+ a+

      with open(file_name,'w',encoding='utf-8') as file_obj:
            r = file_obj.readlines()
      
  • 所有文本文件以外的文件都是二进制文件:音乐文件,视频文件都可以

  • b:读取二进制文件 <读取文本文件时,size以字符为单位,而读取二进制文件时,size是以字节为单位>

文件关闭

  • 方式1:调用close()方法来关闭文件:file_obj.close()

  • 方式2:with … as 语句:

        with open(file_name) as file_obj:
              # 在with语句中可以直接使用file_obj来做文件操作,with结束则文件关闭
              print(file_obj.read())
        示例:
        try:
            with open(file_name) as file_obj:
                  # 在with语句中可以直接使用file_obj来做文件操作,with结束则文件关闭
                  print(file_obj.read())
        except FileNotFoundError:
                  print(f'{file_name} 文件不存在~~~')
    

文件的其他操作

  • seek():可以修改文件读取的位置
    • 参数1:要切换的位置:
    • 参数2:计算位置的方式。可选值:0 从头开始,默认值 1:从当前位置计算 2:从最后位置开始计算
  • tell(): 方法用来查看当前读取的位置
    • print(‘当前读取到了 -->’,file_obj.tell())
  • os.listdir() 获取指定目录的目录结构(所有文件结构)
    • 需要一个路径作为参数,会获取到该路径下目录结构,默认路径为 . 当前目录
    • 该方法会返回一个列表,目录中的每一个文件(文件夹)的名字都是列表中的一个元素;
  • os.getcwd(): 获取当前所在的目录
  • os.chdir(): 切换当前所在的目录,作用相当于cd
  • os.mkdir(): 在当前目录下创建一个名字为 aaa 的目录
  • os.rmdir(‘abc’):删除目录
  • os.remove(‘aa.txt’):删除文件
  • os.rename(‘旧名字’,‘新名字’) 可以对一个文件进行重命名,也可以用来移动一个文件

8 字典的使用

基本点

  • 每个对象都保存了三个数据:id(标识)(相当于C中的内存地址) type(类型) value(值) 可变对象指的是【值】可变;
  • a[0] = 10 通过变量去修改对象的值,这种操作不会改变变量所指向的对象,若有其他变量也指向该对象,则修改也会在其他的变量中体现
  • a = [4,5,6] 给变量重新赋值,这种操作会改变变量所指向的对象,即a的id会重新分配一个;
  • 一般只有在为变量重新赋值时才是修改变量,其余的都是修改对象;
  • 运算符 == 和 != 比较的是对象的值是否相等,is 和 is not比较的是对象的id 是否相等,即比较的是同一个对象;

字典

字典属于一种新的数据结构,称为映射(mapping),其作用和列表类似,都是用来存储对象的容器;在字典中每一个元素都有一个唯一的名字,通过这个唯一的名字可以快速查找到指定的元素。
key-value 每一项都有 键key和值value, 值可以是任意对象,而字典的键需要是任意不可变对象,且不能重复;

  • 创建:
    • { } 如:{k1: v1, k2:v2, k3:v3}
    • d = dict(name=‘sun’,age=‘18’,gender='男‘)
    • 将包含有双值子序列的序列转换为字典: d = dict([(‘name’,‘sun’),(‘age’,18)])
  • 查询:in 和 not in
  • 获取:根据键来获取值,语法:dict[key] 通过[]获取值时,若键不存在,则会抛出异常;通过get(key[ ,default])获取字典中的值,若键不存在,则返回None;
  • 修改:d[key]=value 如果key存在则覆盖,如果key不存在,则加上即可;setdefault(key[ , default]) 若key存在于字典中,则返回key的值,不会对字典做任何操作,key不存在,则添加;
  • 更新:update([other]):将其他字典中的key-value添加到当前字典中,如有重复的key,则后边的会替换到当前的;
  • 删除:popitem() 删除最后一个键值对,删除之后,被删项以元组的形式返回; pop(key[, default])根据key删除字典中的key-value,没有组返回默认值
  • 复制:copy() 对字典进行浅复制()
    • 浅复制copy():复制以后的对象和原对象是独立的,修改一个不会影响另外一个(即两块不同的内存)。但浅复制只会简单的复制对象内部的值,若该值也是一个可变对象,则这个可变对象不会被复制;
      拷贝父对象,不会拷贝对象内部的子对象。例:
      • d = {‘a’:{‘name’:‘sunwukung’,‘age’:18},‘b’:2,‘c’:3}
      • d2 = d.copy()
      • d2[‘a’][‘name’] = ‘bob’ //则都会改变
    • 深复制deepcopy():完全拷贝了父对象及其子对象,连同内部的可变对象一起复制。复制以后的对象和原对象是独立的,修改一个不会影响另外一个。该复制性能差,一般都用浅复制;
  • 遍历:
    • keys() 该方法会返回字典中所有的key: for k in d.keys(): print(k, d[k])
    • items() 该方法会返回字典中所有的项,返回序列在包含有双值子序列,双值就是字典中的key,value. for k, value in d.items():print(k,’:’,value)

集合set

集合和列表非常相似,其不同点在于:1)集合中只能存储不可变对象(列表啥的不行); 2)集合中存储的对象是无序的; 3)集合中不能出现重复元素;
集合运算:在集合作运算时不会对集合本身产生影响;

  • 交集运算 & :两个集合重复的部分: ret = s & s2
  • 并集运算 | :两个集合的和部分: ret = s | s2
  • 差集运算 - :一个集合去除另一个集合没有的部分: ret = s - s2
  • 异或运算 ^ : 两个集合不同的部分: ret = s ^ s2
  • <=: 检查一个集合是否是另外一个集合的子集

9 函数

基本点

  • 不定长的函数参数,def sum(*nums) 可以求任意个数的数字和 此时nums是一个元组(装包) def fn(a,b,*c) 实参1给a,实参2给b,其他的给c;

  • 带星号的参数只能有一个,可以和其他参数配合使用,带星号的参数后的所有参数,必须以关键字参数的形式传递;若形参的开头有一个*,则要求所有
    的参数必须要以关键字参数的形式传递;即在实参传递的时候需要指定;

  • *形参只能接受位置参数,而不能接受关键字参数,而**形参可以接受关键字参数,它会将这些参数统一保存到一个字典中,字典的key就是参数的名字,
    字典的value就是参数的值;例如:def fn(**a): …… 调用时:fn3(b=1,d=2,c=3) 返回:a={b:2,d:2,c:3} 类型为字典;

  • **形参只能有一个,且必须写在所有参数的最后;

  • 参数的解包(拆包)😗 传递参数时,可以在序列类型的参数前面添加*号,这样就自动将序列中的元素一次作为参数传递;
    不过要求序列中的元素的个数必须和形参个数一致;**:通过**可以对字典进行解包操作;
    如:d={‘a’:100,‘b’:200,‘c’:300} function(**d)

  • 函数的返回值return后可以跟任意对象,返回值甚至可以是一个函数,即返回对象就是一个函数;

  • 若仅仅写一个return 或者不写return ,相当于return None;

  • def func1():…… print(func1)和print(func1())的区别:前者func1是函数对象,打印func1实际是在打印函数对象,<function func1 at 0x1111>
    而后者是调用函数,返回是调用函数后的结果。
    ###文档字符串:

  • 定义的文档字符串:在函数的第一行,一般都是对该函数的说明。

  • def fn(a:int, b:bool, c:str=‘hello’) -> int: 显性表示形参的类型和返回值类型,非强制,建议使用

作用域:作用域指的是变量生效的区域

  • python中只有两种作用域:全局作用域 和 函数作用域
  • 全局作用域:
    • 全局作用域在程序执行时创建,在程序执行结束时销毁
    • 所有函数以外的区域都是全局作用域
    • 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
  • 函数作用域:
    • 函数作用域在函数调用时创建,在调用结束时销毁
    • 函数每调用一次就会产生一个新的函数作用域
    • 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
    • 在函数内部为变量赋值,默认都是为局部变量赋值,若希望是在函数内部修改全局变量,则需要使用global关键字,来声明该变量为全局变量
  • 变量的查找:
    • 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用;
    • 如果没有则继续去上一级作用域中寻找,如果有则使用,
    • 如果依然没有则继续去上一级作用域中寻找,以此类推
    • 直到找到全局作用域,依然没有找到,则会抛出异常;

命令空间:变量存储的位置

  • 命名空间实际上是一个字典,专门用来存储变量的字典 scope = locals() print(type(scope)) 即为字典
  • 每一个变量都需要存储到指定的命名空间中,每一个作用域都会有一个其对应的命名空间
  • 全局命名空间:用来保存全局变量
    函数命名空间:保存函数中的变量
  • locals()用来获取当前作用域的命名空间,全局中调用就是获取的全局命名空间,局部中调用就是获取局部命名空间。其返回的是一个字典;
  • 向字典中添加一个key-value就相当于在对应的作用域中创建一个变量,不过一般开发不建议这样做;
  • globals()函数可以用来在任意位置获取全局的命名空间。

10 递归与其他函数知识

递归:自己引用自己,递归式函数:在函数中调用自己

  • 递归式函数的两个要件
  • 基线条件
    • 问题可以被分解为的最小问题,当满足基线条件时,递归就不再执行
  • 递归条件
    • 将问题继续分解的条件
  • 递归和循环类似,基本是可以互相代替的,
  • 循环编写起来比较容易,阅读起来稍难
  • 递归编写起来难,但是方便阅读
  • 例如:斐波那契数列、回文字符串等

高阶函数:接受函数作为参数,或者返回值为函数的函数

  • 当使用一个函数作为参数的时,实际上是将指定的代码传递进了目标函数
  • filter() 函数:可以从序列中过滤出符合条件的元素,保存到一个新的序列中
    • 入参:参数1:函数,使用该函数来过滤序列 参数2:待过滤的序列(可迭代结构)
    • 返回值:过滤后的新序列(可迭代结构)
    • 例如:返回list_a中的所有偶数: ret_2 = list(filter(lambda i: i % 2 == 0, list_a))
  • 匿名函数lambda:专门用来创建一些简单的函数,函数创建的另一种方式
    • 语法: lambda 参数列表:返回值
    • 匿名函数一般都是作为函数使用,其他地方一般不会使用
  • map()函数:map函数可对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回
    • 例如:r = list(map(lambda i: i**2, list_a)) 将list_a中所有的元素求平方
  • sort():对列表中的元素进行排序,默认比较的是列表中元素的大小
    • 可以接受关键字参数key,作为指定排序因子
  • sorted():作用和sort()几乎一样,但是sorted可以对任意的序列进行排序
    • 使用sorted()函数排序不会对原来的对象有影响,而是返回一个新的对象
    • 例如:l = [2,5,‘1’,3,‘6’,‘4’] print(sorted(l,key=int)) 不会对l产生影响

闭包

  • 将函数作为返回值返回也是高阶函数,高阶函数也是一种闭包,通过闭包可以创建一些只有在当前函数才能访问的变量,即将私有数据藏到闭包中;
  • 形参闭包的要素:
    • 1)函数需要嵌套
    • 2)将内部函数作为返回值返回
    • 3)内部函数必须要使用到外部函数的变量

装饰器:可以在不修改源代码的情况下,来对函数进行扩展

  • 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展,在实际开发中,都是通过装饰器来扩展函数功能的;
  • 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数;
  • 可以同时为一个函数指定多个装饰器,这样函数将会安排从内向外的顺序被装饰;越靠近函数的越先被执行
  • 我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
  • ① 如果要修改的函数过多,修改起来会比较麻烦
  • ② 并且不方便后期的维护
  • ③ 并且这样做会违反开闭原则(OCP)
  • 程序的设计,要求开发对程序的扩展,要关闭对程序的修改。即在不修改函数的情况下实现对函数扩展,示例:
          # 后面需要是有begin_end 则只需要在函数开头加上 @begin_end 即可被其装饰
          def begin_end(old):
              '''
              用来对其他函数进行扩展,使得其他函数可以在执行前后做点啥
              参数: old 待扩展的函数
              '''
              def new_function(*args, **kwargs):  # *args 和 **kwargs分别表示是位置参数和关键字参数
                  print('开始执行……’)
                  result = old(*args, **kwargs)     #待扩展的函数  #此处的* 和** 分别表示序列和字典的拆包
                  print(‘执行结束……‘)
                  return result
              #返回新的函数
              return new_function
    

11 面向对象编程-基础

对象 是内存中专门用来存储数据的一块区域,可以存储任何类型数据(数字,布尔值,代码)。类是一个type类型的对象。

  • Python面向对象__new__()和__init__()的使用
    • __new__()被用来创建新的实例对象,在类的方法定义中经常被定义为静态方法。第一个参数是cls,其余参数是创建实例所需的信息,
      必须有一个返回值作为后续使用的对象实例:object.__new__(cls,[,…])

    • __init__()被用来初始化被__new__()创建出来的实例对象,它的处理过程在用户拿到对象实例之前完成。

    • __new__()和__init__()都是Python基础对象object已经实现的方法,我们平时在自定义类的书写过程属于“override”。
      __init__()的使用更为频繁,导致大家经常会把__init__()方法认为是构造的全部过程。实际上__new__()偏重对象实例的创建过程,
      __init__()偏重对象实例的初始化过程,两者加起来才是Python中一个类构造对象实例的全部过程。

  • 类 class
    • int() float() bool() str() list() dict() 这些都是python的内置类
    • isinstance() 用来检查一个对象是否是一个类的实例:ret = isinstance(cla,class) #检查cla是不是class的一个实例
  • 实例化之后对象,其类型就是母类。如 myclass = MyClass() 其类型就是MyClass
  • 类和对象实际上有两部分组成,1)数据(属性) 2)行为(方法)
  • 方法调用和函数调用的区别:
    • 函数调用,调用时传递几个参数,就会有几个参数;
    • 方法调用,默认传递一个参数(第一个参数有解析器自动传递),所以在方法中至少需要定义一个形参;

特殊方法(魔法方法)

  • 特殊方法的都是以__开头,以__结尾的方法;
  • 特殊方法不需要我们自己调用,不需要尝试调用特殊方法,其会在特殊时刻自己调用;

封装:

隐藏对象中一些不希望被外界所访问的属性和方法,面向对象的三大特性之一

  • 如何获取(修改)对象中的属性:
    • 需要提供一个getter和setter方法使外部可以访问到属性
    • getter 获取对象中的指定属性(get_属性名)
    • setter 用来设置对象的指定属性(set_属性名)
  • 使用封装,虽然复杂程序增加,但是确保了数据的安全性
  • 1.隐藏了属性名,使调用者无法随意的修改对象中的属性
  • 2.增加了getter和setter方法,很好的控制的属性是否是只读的
    • 如果希望属性是只读的,则可以直接去掉setter方法
    • 如果希望属性不能被外部访问,则可以直接去掉getter方法
  • 3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
  • 4.使用getter方法获取属性,使用setter方法设置属性
    • 可以在读取属性和修改属性的同时做一些其他的处理
  • 5.使用getter方法可以表示一些计算的属性
  •       class Dog:
            '''
            Dog 大类  hidden_name 和 hidden_age不对外暴露
            '''
            def __init__(self, name, age):
              self.hidden_name = name
              self.hidden_age = age
          
            def say_Hi(self):
              print("Hi,I am %s"% self.hidden_name)
              #print("Hi,I am " + self.hidden_name, ", and I am "+ str(self.hidden_age)+" years old!")
          
            def get_name(self):
            # get_name()用来获取对象的 name属性
              return self.hidden_name
          
            def set_name(self, name):
              self.hidden_name = name
          
            def get_age(self):
              return self.hidden_age
          
            def set_age(self, age):
              if age > 0:         #这里可以对age作一个检查
                self.hidden_age = age
    

隐藏属性

可以为对象的属性使用双下划线开头,__xxx,这种属性就是对象的隐藏属性,

  • 隐藏属性只能在类的内部访问,无法通过对象访问;
  • 隐藏属性其实就是python为属性改了一个名字,将属性名字改为: _类名__属性名。如:_Person__name
  • 一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
  • 一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
  •     class Person:
          def __init__(self, name):
            self._name = name    # _name即为私有属性
          def get_name(self): 
            return self._name
    

Property装饰器

将一个方法变成一个静态属性,给用户更简单的调用方式,隐藏具体的实现细节。

  • 添加为property装饰器以后,我们就可以像调用属性一样使用get方法;
  • 使用property装饰以后,必须和属性名一样
  •   class Person:
        def __init__(self, name, age):
          self._name = name 
          self._age =age
    
        @property 
        def name(self): 
          return self._name
    
        # setter方法的装饰器:@属性名.setter  
        # 有setter则必须要有  @property
        @name.setter
        def name(self,name):
          self._name = name
      # 后面在调用的时候: P = Person()   P.name ='sun'  #即可以像其属性一样直接用
    

12 面向对象编程-继承/多态

继承与多重继承

继承是面向对象的三大特性之一,通过继承可以使一个类获取到其他类中的属性和方法:

  • 在定义类时,可以在类名后的括号中指定当前类的父类(超类,基类,Super),子类(衍生类)可以直接继承父类中的所有属性和方法
  • 继承可以直接让子类获取到父类的方法和属性,避免编写重复性的代码,并且也符合OCP原则,在实际代码开发中经常需要对一个类进行扩展。
  • 在创建类时,如果忽略了父类,则默认父类就是object
  • issubobject(A, B) #检查一个类A 是否是另一个类B的子类。(不能反着检查)
  • 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法。以扩展多余的属性;
  • super:通过super 可以动态的获取当前类的父类,通过super返回对象调用父类方法时,不需要传递self。
  • class Dog(Animal):
      def __ini__(self,name,age):
        # 可以直接调用父类的__init__来初始化父类中定义的属性,super()可以用来获取当前类的父类
        super().__init__(name)    #相当于Animal.__init__(name)
        self._age = age
    
  • 多重继承:使子类同时拥有多个父类,并且会获取所有父类中的方法。(实际开发中尽量少用,避免对于复杂)
    • python中是支持多重继承的,可以同时为一个类指定多个父类:在类名后面的()后边添加多个类,来实现多重继承;
    • 如果有多个父类中的有同名的方法,则会出现第一个父类中寻找,然后找第二个,第三个,前面父类的方法会覆盖后面父类的方法。

重写

重写(覆盖,override)

  • 如果在子类中如果有父类同名的方法,则可以通过子类实例去调用方法时,会调用子类的方法
    而不是父类的方法。
  • 当我们调用一个对象的方法时,
    会优先去当前对象中寻找是否具有该方法,如果有则直接调用;
    如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法;
    如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错;

多态

面向对象的三大特征之一,多种形态:一个对象可以以不同的形态去呈现

  • isinstance(obj, A) 若对其他类型做出限制,使得其他类型的对象都无法使用这个函数,则该函数违反了多态原则;
  • 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型的对象,这样导致函数的适应性很差。
  • isinstance 在实际开发中基本不用,因为一旦用了就违反了多态。
  • 多态名言:如果一个对象走路像鸭子,叫声像鸭子,形态像鸭子,那么它就是鸭子。
    ###面向对象三大特征:
  • 封装:确保对象中的数据安全
  • 继承:保证了对象的可扩展性
  • 多态:保证了程序的灵活性
    ###垃圾回收
    在程序中没有被引用的对象就是垃圾,垃圾对象过多会影响到程序的运行的性能;
  • 删除特殊方法: def __def__(self):
    print('A()对象被删除……'self)

特殊方法

  • str(self): 作用是用来指定对象转换为字符串的结果(print函数)

  • 特殊方法(魔法方法)会自动执行,不需要手动调用;

  • 可以修改其内部特殊函数以满足特殊情况:

    class A():
      def __gt__(self,other):
        return self.age > other.age  #根据两个对象的age比较,self的age大于other即返回True;
    

模块与包

模块化:在python中一个PY文件就是一个模块,想创建模块就是创建一个python文件。可以将容器理解为一个容器,在容器里面的都可以被引用
  • 从一个模块中引入另一个模块: 1)import 模块名 2)import 模块名 as 模块别名
  • 可以引入同一个模块多次,但是模块的实例只会创建一个
  • import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头
  • 在每一个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
  • __name__属性值为 __main__的模块是主模块,一个程序中只会有一个主模块
  • 引入一个模块中的部分内容: from 模块名 import 变量,变量……
  • print(test_module) #可以打印出该模块的位置
包:当模块中代码过多时,或者一个模块需要被分解为多个模块时,就需要使用到包
  • 普通的模块就是一个py文件,而包是一个文件夹
  • 包中必须要有一个 __init__文件,这个文件可以包含包中的主要内容
  • from test import * #从test 中引入所有的内容(相当于把test中的代码都拷贝进来)

13 面向对象编程-模块化/异常

在Python中,一个类可以有:类属性,实例属性,类方法,实例方法,静态方法

  • 类属性:直接在类中定义的属性。类属性可以通过类或类的实例访问到,但只能通过类对象来修改,无法通过实例对象修改;
    • 类属性中一般存储公共的属性部分;
  • 实例属性:通过实例对象添加的属性属于实例属性。实例属性只能通过实例对象来访问和修改,类对象无法访问修改;
  • 类方法:在类内部使用 @classmethod 来修饰的方法属于类方法。
    • 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象;
    • 类方法和实例方法的区别:实例方法的第一个参数是self,类方法的第一个参数是cls;
    • 类方法可以通过类调用,也可以通过实例调用,没有区别;
  • 实例方法:在类中定义,以self为第一个参数的方法都是实例方法。
    • 实例方法在调用时,python会将第一个参数self自动传入;
    • 实例方法可以通过实例和类去调用;
      • 通过实例调用时,会自动将当前对象作为self传入;
      • 通过类调用时,不会自动传递self,需要手动传递self参数;
  • 静态方法:在类中使用 @staticmethod 来修饰的方法属于静态方法
    • 静态方法基本上是一个与当前类无关的方法,只是保存在当前的类中的函数;
    • 静态方法不需要指定任何默认参数,静态方法可以通过使用类和实例去调用;
    • 静态方法一般都是工具方法,和当前类无关;

python类中Staticmethod Classmethod 和 property的区别:

    @Staticmethod 和 @Classmethod可以不需要实例化一个对象,直接用类名.方法名()来调用, staticmethod不需要表示自身对象的self和自身类的cls参数,
    就和使用函数一样;classmethod不需要self参数,但是第一个参数需要表示自身类的cls参数;
    1)在类中使用 @staticmethod 来修饰的方法属于静态方法,可以看成是一个完全独立的函数,只是调用的时候必须通过这个类,
    一般是为了规范代码而实现的,类中定义函方法 PyCharm 提示Method xxx may be ‘static’, 原因是该方法不涉及对该类属性的操作,编译器建议声明为@staticmethod,面向对象思想体现。----就是作为一般的工具函数来使用  
    静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用  
    静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
    静态方法一般都是一些工具方法,和当前类无关
  
    2)classmethod类方法:只能访问类变量,不能访问实例变量, 也就是跟类有关,跟实例无关:
    在类内部使用 @classmethod 来修饰的方法属于类方法
    类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
    类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls    
    类方法可以通过类去调用,也可以通过实例调用,没有区别
  
    3)property属性方法的作用通过@property把一个方法变成一个静态属性;
    @property属性方法 封装类中的方法,给用户更加简单的调用方式,隐藏具体的实现细节。
    @method.getter 获取属性
    @method.setter 设置属性, 可以写更多逻辑(比如格式转换,类型判断),并提醒其他人这里面可能有magic
    @method.deleter 删除属性

标准库

开箱即用,为Python提供了一个模块的标准库,如 sys模块提供了变量和函数,可以获得python解析器的信息

  • os.environ() #通过该属性可以获取到系统的环境变量
  • os.system() #可以用来执行操作系统的名字 os.system(‘dir’)
  • _c = 30 # 添加了_c的变量,只能在模块内部访问,在通过 import *引入时,不会引入_开头的变量

主模块

  • 这部分代码只有当前文件作为主模块的时候才需要执行,而当其他模块引入时,不需要执行,我们就必须要检查当前
    模块是否是主模块
    if name == “main”:
    ……

__pycache__文件

模块的缓存文件,py代码在执行前,需要被解析器先转换为机器码,然后再执行,我们在使用模块(包)时,也需要将模块代码
先转换为机器码,然后再交给计算机执行。

  • 为了提高程序运行的性能,python会在编译过一次后,将代码保存在一个缓存文件中(.pyc文件)

异常及异常对象

程序在执行过程中难免会出现异常:使用了没有复制过的变量;使用了不存在的索引;除 0等

  • 将可能出现错误的代码放在 try 中:

    try:
      print(10 / 0)   #  将可能出错的代码放在try中
    except:
      print('HaHaHa,出错了')
    else:
      print('程序正常执行没有错误’)
    
  • 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播;如果函数中没有对异常进行处理,
    则异常会继续向函数调用处传播;若调用处处理了则不再传播,否则报错时都会显示出错误的行数。

异常对象

  • 我们可以针对异常对象类型做出调整,常见的异常对象类型有:

    • NameError 异常
    • ZeroDivisionError 异常
    • IndexError 异常
  • 如果except后不跟任何的内容,则此时它会捕获到所有的异常

  • Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常

  • 如果后面跟着一个异常类型,则它只会捕获该类型的异常
    示例:

    try:
      print(10 / 0)   #  将可能出错的代码放在try中
    except NameError:
      # 如果except后不跟任何的内容,则此时它会捕获到所有的异常
      print('NameError 异常')
    except ZeroDivisionError:
      print('ZeroDivisionError 异常')
    except IndexError:
      print('IndexError 异常')
    except Exception as e:
      print('未知异常',e,type(e))
    finally:
      print('无论是出现异常,该语句都会执行到')
    
  • 也可以自己定义自决定异常类,只需要创建一个类继承Exception即可

  • raise 用于向外部抛出异常:raise(’两个参数中不能有负数‘)

    class MyErro(Exception):
      pass
    def add(a, b):
      if a < 0 or b < 0:
        raise MyError('自定义异常’)
      r = a + b
      return r
    print(add(-123,345))  #会抛出自定义的异常
    

Python 基础进阶

平台:华为云

函数

不定长参数:有时候需要处理一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数,声明时不会命名。

  • *args:args会存放所有未命名的变量参数,args为元组;
  • **kwargs:kwargs会存放命名参数(以字典的方式传值),即形如key=value的参数,kwargs为字典。
  • 在函数中,各种参数的存放位置为:def func(必备参数,关键字参数,默认参数,不定长参数)

对象

  • 在默认情况下,属性在Python中都是public,类所在模块和导入了类所在模块的其他模块都可以访问到。如果类中的某些属性不想被外界访问或者继承可以对其私有化;
  • 模块级的私有化:在属性或方法前加上一个下划线_即可。防止模块的属性用“from mymodule import *”来加载,它只可以在本模块中使用。
  • 完全私有化:只能自己访问。在方法或属性前加双下划线__。Python中的完全私有化是一个假的私有化,它的作用其实是将之前的属性或方法名改为了‘类名._属性/方法’
  • 常用的魔法方法:
    - new(cls[,]):创建实例时首先调用的方法(构造方法)
    - init(self[,]):对象初始化方法(new方法返回对象后,调用init方法进行属性的初始化)。
    - del(self):析构方法,当实例化对象被彻底销毁时调用(实例化对象的所有指针都被销毁时调用)
    - getattr__(self,name)定义当用户试图获取一个不存在的属性时的行为;
    - setattr__(self,name,value)定义当一个属性被设置时的行为。
    - getattribute__(self,name)定义当该类的属性被访问时的行为。访问对象属性或方法时,首先被调用的方法。
    -

设计模式

单例模式:单例模式中单例类只有一个实例(单例类必须自己创建自己的唯一实例)

  • 单例类必须给所有其他对象提供这一实例。
  • 在python中可以使用__new__来实现单例。

Python中的轮子/模块/包

轮子:在程序中,我们将封装好的组件、库称之为轮子。可以直接拿来用,实现对应的功能。
模块:一个.py文件就是一个模块。 模块是Python中的最高级别组织单元,它将程序代码和数据封装起来以便重用。模块的三个作用:1)代码复用 2)系统命名空间的划分 3)实现共享服务和数据。
包:是一个目录,要被Python视为包,目录中必须含有__init__.py文件,包的导入会首先执行__init__.py文件。其他模块加入包中,放入包的目录即可。
上图为一般Python程序结构模式

  • import搜索的路径顺序:以下四个组件组合起来就变成了sys.path,其保存了模块搜索路径在机器上的实际配置。可以通过打印内置的sys.path列表来查看这些路径。
    - 程序的主目录
    - PythonPath(环境变量)目录
    - 标准链接库目录
    - 任何.path文件内容

Python场景内置工具包

  • os:负责程序与操作系统的交互,提供了访问操作系统底层的接口;
    - os.getcwd():获取当前所在路径
    - os.chdir(path):改变当前工作目录
    - os.listdir():返回目录下所有的文件
    - os.walk():返回目录下所有文件(包括子文件夹中的文件)
    - os.path.join(path):按照当前系统所能识别的方式链接目录名 根据系统的不同加的连接符号是不一样的,适应性更强。
    - os.path.abspath(path):返回绝对路径
    - os.path.exists(path):文件存在则返回True,不存在则返回False
    - os.path.getsize(path):返回文件大小
  • sys:负责程序与Python解释器的交互,提供了对解释器的一系列的函数和变量的访问,用于操控Python运行时的环境。
    - sys.exit([n]):此方法可以是当前程序退出
    - sys.path:获取模块搜索路径列表 path是一个目录列表,供Python从中查找模块
    - sys.argv:从程序外部向程序传递参数,参数以列表的形式传递,第一个为当前文件名。如python m.py argv1 m.py是第一个参数。

文件读写

常见操作

  • f.tell():返回当前文件读写位置
  • f.seek(off,where):定位文件读写位置。off表示偏移量,正数向尾部移动,负数向开头移动。where为0表示起始位置开始,1表示当前位置,2表示结尾位置。
  • with open(file_name, mode,encoding) as f:
    文件操作语句 使用后会自动关闭文件
  • with open(“数据分析/data.csv”,‘r’) as f:
    print(f.read())
    借助pandas库可以更好的读取数据

其他技巧

小整数对象池

Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间。小整数范围[-5,256]。在此范围之内的数据,指向同一块内存地址。如:
a = 0 b = 0 id(a) == id(b) 返回True。在此范围之外的一般为False。

  • 这些整数对象会被事先建立好,不会被回收,为变量赋值时直接指向这些建立好的地址。
  • 这些优化在简单字符串上也有。简单字符串(不含空格和其他特殊字符)在内存地址中是一起的。如:
    a = “python” b = "python” a is b 返回True。

动态语言的体现

  • 在Python中声明变量时不需要指定类型。
  • 在类和对象的使用中可以动态的为对象添加属性和方法。
  • Python中的垃圾回收机制以引用计数为主,以隔代回收为辅进行的。

其他技巧

  • eval函数会将输入的字符串拆除两边引号,直接计算其值。
  • 在Python字典中,key具有等效性。6 == 6.0 = 6 + 0j
  • Python可以这样给元组排序:
l = [(1,2), (2,4),(2,3),(3,2)]
l.sort(key = lambda x:(x[0], x[1]))   # key指定排序关键字  指派x[0]  x[1]
  • Python是动态语言,在运行过程中是实时变换的。如在删除列表元素的过程中,列表的长度是实时变化的:
l = [99, 100, 46,68,44,50,78,50,59,66,51,89,54]
for i in s:
	s.remove(i)    #删除一个元素后,列表的长度实时变化

常见应用

正则表达式

正则表达式是一个由特殊字符串组成的字符串,这个特殊的字符串描述了匹配的一系列字符的规则。正则表达式为高级的文本模式匹配、抽取、与/或文本形式的搜索和替换功能提供了基础。大多数编程语言中的正则表达式的书写规则形式和规则是一样的。
大致匹配过程:
依次将文本中的字符和正则表达式做匹配,如果所有字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。

  • python中通过正则表达式对字符串进行匹配的时候,需要使用标准库re模块:re模块中通过给定的匹配规则,匹配文本中符合规则的字符并进行操作。匹配的规则可以是字符串,也可以是正则表达式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值