Python基本语法

计算机相关的名词知识

1.1计算机的组成

根据计算机之父冯诺依曼,根据冯诺依曼的结构体系,计算机时分为5部分的

  1. 输入设备 把信息传递刀计算机中,比如键盘,鼠标
  2. 输出设备 信息v哦那个计算机中传递出来,比如印象,显示器,打印机等等
  3. 存储器 计算机被发明出来就是用于数据的存储与计算的
    1. 内存 内存是用来存储计算机上应用运行产生的数据【内存中的数据,当程序退出的时候,该程序存储于内存中的数据都会被释放】内存在之后的知识中会有提及【python编写的程序运行产生的数据时存储于内存中的
    2. 硬盘 电脑上的磁盘分区,存储在硬盘中的数据都是持久化存储【只要不删除就一直存在】
  4. 运算器 调度存储器中的数据参与相应的运算【基本运算有加减乘除】
  5. 控制器控制器和运算器结合在一起称为中央控制器【CPU,相当于人的大脑,调度计算器各部分的运转】

1.2命令行交互的一些指令

人与应用程序交互的模式,这个模式常见的是由两种

  1. 图形化界面(Windows)

    接触起来比较简单

  2. 命令行

    之后可能会接触一些文件操作相关的指令,介绍一些常用的指令,在Windows系统中成为DOS命令,在Mac或者Linux系统中成为Shell命令

    这个指令是需要在终端上运行,这个工具在Mac上称为终端,在Windows上称为命令提示符工具(CMD)

    启动工具的方式(工具启动完成, 默认打开的是当前用户的路径)

    1. Windows下可以使用快捷键win + r调出搜索器,输入cmd回车进行启动
    2. Mac在启动台上找到其他-终端

    Mac和Windows目录结构不一样

    • Windows是分磁盘的,分为C盘,D盘,但是Mac下没有分盘,所有路径都是从根目录/来的

    常用的一些指令

    主要是来解除目录的跳转

    1.显示当前目录下的子文件
        Windows:dir
        Mac:ls
      显示隐藏文件的话
        Windows:dir /a
        Mac: ls -la
    2.路径的切换
      Windows、Mac:cd + 文件路径
          例如:cd C:\Program Files (x86)\ASUS
      文件路径分为两种
          1.绝对路径  比如 C:\Program Files (x86)\ASUS
          2.相对路径
            记住两个符号
            .  一个点表示当前目录
            .. 两个点表示上级路径
      注意,Windows下面可能涉及到盘符的切换,路径盘符与当前盘符不一致,需要切换盘符
      命令:  
      盘符:回车即可,例如  D:
    

1.3计算机中数据存储

生活中的计算数据的时候是按照十进制规则来进行计算的

十进制的规则是逢十进一,十进制的数字符号是由0/1/2/3/4/5/6/7/8/9组合成的

计算机中数据存储运算的时候,不是采用的十进制,而是二进制这个二进制就是逢二进一,二进制的数字符号只有0和1

常见的进制形式:二进制、八进制、十进制、十六进制

二进制(0b –binary):符号集只有0和1,**0b10**代表的是数字2

八进制(0o –octal) :符号集0/1/2/3/4/5/6/7, 0o10代表的是数字8

十进制:符号集0-9,10代表就是数字10

十六进制(0X – hexadecimal):逢十六进一,就意味着没有遇到16不会出现两位数,0x16代表的是数字16,符号集0/1/2/3/4/5/6/7/8/9/a/b/c/d/e/f在十六进制中使用字母a-f表达10-15的数字【字母大小写都可以】

八进制和十六进制出现的原因是因为二进制表达数据可读性差,组合会过于长,因此出现了八进制和十六进制,简化二进制的表达格式

进制转换

  1. 十进制转化为二进制的规则

    整数部分规则
        将数据除以2取余数,重复这个操作,知道商为0,将所有余数逆向拼接,结果就是二进制数据
        比如:24 == 0b11000
        24/2=12 ---0
        12/2=6  ---0
        6/2=3   ---0
        3/2=1   ---1
        1/2     ---1
    小数部分的规则
        将数据乘以2取整数部分,再将积的小鼠部分乘以2取整数部分,重复此操作,直到小数部分为0,将整数部分正序拼接在一起
        比如:0.125= 0b.001
        0.125 * 2=0.25  ---0
        0.25 * 2 0.5    ---0
        0.5* 2=1        ---1
    
  2. 二进制转十进制

    规则:按权展开求和
        以十进制为例,讲解这个按权展开
        比如 0b1101=
            1 * 2^0 + 0 * 2^1 + 1*2^2 + 1* 2^3
            =1 + 0 + 4 +8
            =13
        
        二进制比较特使,特殊的就是符号集只有0和1,0乘以任何书为0,1乘以任何数为数据本身,可以假设所有位置上都是1,二进制数据每位的权值从右到左的结果为1 2 4 8 16 32 64 128.。。。
        另外简便的规则
            将数据减去离其最近且小于它的2的幂数,将差值继续该操作,直到差值为0,统计2的幂数有哪些,然后按照从右向左的位置 有该幂数的则该位置为1,否则对应位置为0、
            比如 79 = 64+8+4+2+1
            64  32  16  8  4  2  1
            1   0   0   1  1  1  1
            所以就是1001111
    
  3. 八进制和二进制之间的转换

    八进制转二进制规则:
        八进制的最大数字是7,7转化为二进制需要三位,为0b111,最大的数字选哟三位,其他的数字三位足以满足要求
        规则,将二进制数据从右向左三位三位一分,左边不足三位前面补0,将分出的每一份按权展开求和,将和从左向右拼接在一起就是八进制
        比如 0b 1100111011
        0b 001 100 111 011
           1   4   7   3  
        所以0b 1100111011转化为二进制为0o1473
    
  4. 十六进制和二进制之间的转换

    十六进制转二进制规则:
        八进制的最大数字是f(15,7转化为二进制需要四位,为0b1111,最大的数字选哟四位,其他的数字四位足以满足要求
        规则,将二进制数据从右向左四位四位一分,左边不足四位前面补0,将分出的每一份按权展开求和,将和从左向右拼接在一起就是八进制
        比如 0b 1100111011
        0011 0011 1011
         3   3    b
        所以0b 1100111011转化为十六进制为0x33b
    

    练习

    八进制转二进制
        0o756
        0o354
    十六进制转二进制
        0xaf39
        0xbcd7
    

​ 备注:八进制或者十六进制转化成十进制,规则也是按权展开求和;八进制和十六进制之间的转化需要以二进制为桥梁进行操作【先转二进制,在做转换】

5.

八进制转十进制
    0o112 = 2*8^0 + 1*8^1 + 1*8^2
          = 2 + 8 + 64 = 74
十进制转八进制
    数据除以8取余数,再用商除以8取余数直到商为0 将余数逆向拼接
    78 = 0o116
    78/8 = 9 --- 6
    9/8 = 1 ---- 1
    1/8 = 0 ---- 1
十六进制转十进制
    0xff = 15*16^0 + 15 * 16^1
         = 15 + 240
         = 255
十进制转十六进制
    数据除以16取余数,再用商除以16取余数直到商为0 将余数逆向拼接
    255 = 0xff
    255/16 = 15 -- 15
    15/16 = 0 ---- 15
八进制和十六进制之间的转换
    0xff === 0o377
        0xff = 0b011 111 111
                =0o377

1.4编码和解码

计算机中数据的存储格式是二进制格式的,计算机被研发出来作用就是存储和计算的。

编码:常见的一些数据存储与计算机中是如何存储的,这个规则称之为编码

常见的一些数据【数字、文字、图片、音视频等等】‘

进制转换中数字可以通过规则转换成二进制进行存储,比如10可以转换成0b1010,但是文字【汉字、英文字母或者各国预言】这些如何进行存储?

因为数字可以直接存储,制定存储规则的逻辑将每个文字都映射一个数字,将数字转化为二级制数据进行存储,这种规则称为编码

常见的编码方式有

  1. ASCII码怕【美国信息交换标准代码】只有128个文字符号

    需要记住的就是字符0-9 小写英文字母a-z 大写英文字母 A-Z

    • 字符0对应十进制数据是 48
    • 字符a对应十进制数据是 97
    • 字符A对应的十进制数据是 65
  2. GB2312/GBK

    国家编码标准,简称国标,兼容ASCII

  3. Unicode

    国际编码标准看,收录的世界语言

    Unicode下又分为很多种,常见的是其中的UTF-8

不同编码的存储区别:

  1. ASCII属于了单字节编码方式,里面规定的字符,在内存中存储的时候开辟的一个字节进行存储的
  2. GBK/GB2312存储汉字的时候规定汉字字符在呢村中占2个字节
  3. UTF-8存储汉字的时候,规定汉字字符在内存中占3个字节

计算机中数据的存储格式是二进制,数据在存储的时候单位有哪些?

  1. 位(bit)指二进制数据中的一位,例如0b10就是两位
  2. 字节(Byte)一个字节等于8位1B=8b
  3. 千字节(KB)1KB = 1024B
  4. 兆字节(MB) 1MB = 1024KB
  5. 吉字节(GB) 1GB=1024MB
  6. 太字节(TB) 1TB=1024GB

存储的时候开辟的最小的单位就是字节

编码:把文字数据编译成计算机中存储的二进制数据的过程称为编码

解码:把计算机中存储的二进制数据的数据解码成文字数据成过程称为解码

1.5编程语言

语言:沟通交流信息的方式,有效信息的传递包含三部分:传递者/接收者/共识信息【两方都能听懂表达的含义】

编程语言:人们想要和计算机打交道,并且让计算机帮我们做一些事情,主动传递者需要向计算机传递一些计算机能听懂的语言,这个语言就叫做比编程语言

编程语言分为低级编程语言和高级编程语言

  1. 低级语言包含机器语言、汇编语言

    机器语言直接通过0和1指令与计算机进行交互

    汇编语言使用一些容易理解的单词来代替指令与计算机进行交互

  2. 高级编程语言

    • 编译型编程语言

      写的代码计算机没有办法直接识别,需要将程序问价你编译成计算机额能识别的文件,再对文件中的内容逐行解释给计算机,让计算机完成相应的操作。例如java

    • 解释型编程语言

      直接对程序文件逐行向计算机进行解释,完成指令操作。例如python

1.6 Python解释器程序的安装

Python官网www.python.org推出自己的解释器软件, 这个工具安装完成之后包含着解释器以及Python程序编写相应的一些工具库文件

Anaconda集成环境工具,除了有Python解释器及其自带的一些Python程序编写相应的一些工具库文件之外,额外安装好了180多个数据科学计算包 【这个工具包对于官方提供的属于第三方,要使用的时候是需要自己来进行安装的】

版本号的解读:Python 3.11.5

一般格式为A.B.C

C — 程序中出现小问题,修复之后发行的版本

B — 程序中增加了新的功能 发行的版本

A — 程序重构 重新发行一版新的

注意:编程语言环境一般不建议使用最新的,避免有些工具库没有适配到新环境,这个工具库就不能使用了,建议使用稳定的环境 Python3.8/3.9/3.10

安装成功之后,软件解读

  1. C:\Software\Anaconda3\python.exe 解释器,由它向计算机解释写的每行Python代码的含义
  2. C:\Software\Anaconda3\Lib Python环境下工具库的目录【这些工具库都是原生的,可以直接使用的】
  3. C:\Software\Anaconda3\Lib\site-packages 三方工具库的目录 【这些工具是需要额外安装的】
  4. C:\Software\Anaconda3\Scripts\pip.exe 管理工具库的软件 【负责下载、安装、卸载等等工具库的软件】

全局变量Path的解读

问题:为什么安装anaconda的时候要把Python解释器路径放在全局变量PATH下???【方便在任意位置获取解释器解释Python程序】

写代码的时候代码文件可以在任意的目录下,但是python.exe这个解释器文件想要发挥作用只能在安装路径下能找到

在终端上书写python 的时候 没有限制路径,查找顺序是

  1. 在全局路径path下进行查找有没有文件夹中包含这个执行文件的,有的话直接调度运行, 如果没有就进行第2步
  2. 查看cmd当前路径下有没有该执行文件,有的话直接调度执行,如果没有提示既不是内部命令 也不是外部命令

全局路径设置的流程:

​ windows的设置流程:

​ 此电脑 - 右键 - 属性 - 高级系统设置 - 环境变量 - 用户变量[仅针对于当前用户]/系统变量[针对于所有用户] - PATH

检查有没有配置好这个全局路径,启动终端,书写Python回车检查是否能够进入到Python环境下 ,退出环境就是 exit()

C:\Users\liuyanan>python
Python 3.8.8 (default, Apr 13 2021, 15:08:03) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32

Warning:
This Python interpreter is in a conda environment, but the environment has
not been activated.  Libraries may fail to load.  To activate this environment
please see https://conda.io/activation

Type "help", "copyright", "credits" or "license" for more information.
>>>exit()

1.7 开发工具的安装

利用可视化工具编写代码,软件使用的是pycharm[集成开发工具]

集成开发工具就是集编写代码、运行代码、调试代码于与一身的开发工具

关于pycharm的设置

  1. 设置主题 File | Settings | Appearance & Behavior | Appearance - Theme

  2. 设置编辑区的背景图 File | Settings | Appearance & Behavior | Appearance|background image

  3. 设置字号字体 File | Settings | Editor | Font

  4. 设置解释器 File | Settings | Project | Python Interpreter

  5. 设置文件表头 File | Settings | Editor | File and Code Templates | Python Script

      可用的预定义文件模板变量为:
      ${PROJECT_NAME} - 当前项目的名称。
      ${NAME} - 在文件创建过程中在“新建文件”对话框中指定的新文件的名称。
      ${USER} - 当前用户的登录名。
      ${DATE} - 当前的系统日期。
      ${TIME} - 当前系统时间。
      ${YEAR} - 今年。
      ${MONTH} - 当月。
      ${DAY} - 当月的当天。
      ${HOUR} - 目前的小时。
      ${MINUTE} - 当前分钟。
      ${PRODUCT_NAME} - 将在其中创建文件的IDE的名称。
      ${MONTH_NAME_SHORT} - 月份名称的前3个字母。 示例:1月,2月等
      ${MONTH_NAME_FULL} - 一个月的全名。 示例:1月,2月等
    
    """
    项目名称: ${PROJECT_NAME}
    用户名: ${USER}
    创建日期: ${DATE}
    flag标语:键盘敲烂 月薪过万!!!!
    """
    

2.Python基本语法知识

2.1代码初尝试

Python中输出功能为print(输出的数据)

  1. 数据如果是数字,直接写print()
  2. 数据如果是文本,书写的时候需要加引号【单双引号都行】

print('helloworld)

2.2.1编码规范

语句:完成逻辑的表达式称为语句

再次编程语言中习惯语句结束的时候使用分号作为标志,但是在python中不建议使用;作为结束符号

但是当一行中又很多语句时,必须使用分号

空格缩进:在python中体现代码块包含的意思【有些代码要满足条件才能执行,是需要被包含在一个条件内的】

2.2.2注释

程序员为了更好的解读代码,给代码添加的标注,这个标注不被计算机当作程序识别,或者有些功能暂时不被启动,需要将代码进行注释

  1. 单行注释

    格式:#空格

  2. 多行注释

    格式:可以是三对单引号或者三对双引号,规范应该用**三对双引号**

2.3print的使用

# print的使用  按住ctrl键 点击功能名称
# print()
# print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
"""
1.value, ..., 代表的是print可以一次性输出多个数据,书写的时候,数据之间使用逗号隔开 
2.sep=' '  代表的是print一次性输出多个数据展示结果时,数据之间的分隔符默认为空格
        也可以进行修改, 为了避免print将设定的分割符识别成输出的数据,设置分割符的时候格式为
            print(数据1, 数据2, 数据3, sep=分隔符)
3.end='\n' 代表的是print输出内容的结束符,这个结束符默认是换行
        一个知识点: 转义符\,可以将某些特定的符号转变其他的含义
            比如符号n  加上\就变成换行符  \n
            符号t  \t代表的是tab键 称为制表符 【四个空格】
            符号u  会把u后面的内容当做unicode编码 想去获取其对应的文字
                4e00 ===> 一
        因为end默认是换行 所以每个print打印的结果都是独占一行的
            也可以对end进行修改 修改格式类似于sep 
            print(数据1, 数据2, 数据3, sep=分隔符, end=结束符)
"""
print(10)
print('hello world')
print(10, 20, 30, 40)

# 打印的时候 分隔符没有使用sep指定  会被识别成多个数据中的一个进行打印输出
print(10, 20, 30, 40, '+')  # 10 20 30 40 +
# 想要展示内容使用+分割 必须使用sep指定
print(10, 20, 30, 40, sep='+')  # 10+20+30+40

# 转义符
print('and')  # and
print('a\nd')
"""
a
d
"""
print('heath')  # heath
print('hea\th')  # hea	h

print('\u4e00')  # 一

# 报错 报错的原因是 把sers当做了unicode编码  但是sers没有对应的文字
# print('\Users')

# 修改结束符
print(10, end='\t')
print(20)  # 10	20
4.file=sys.stdout 代表的是内容输出的目的地, 默认是控制台上的输出
    演示把内容输出到文件中
        目的:要在一个文件中写内容
        #如何使用pyhton代码按照路径打开文件
        使用open函数
            格式:open(文件路径,操作模式,encoding=文件存储编码形式)
            绝对路径 从盘开始一直到具体的文件
            相对路径 仙姑低于现在的路径
            ..表示上一级路径
            ./demo.py 这个文件就在现在的路径下
            ../demo.py 这个文件在上一级路径下
            ../../demo.py 这个文件在上上级路径下
        操作模式
        w  ——write
            如果路径对应的文件不存在 会先创建文件 再写入
            如果文件存在,会清空文件 再写入
        a ——append
            如果对应的文件不存在  会先创建文件再写入
            如果文件存在,不会清空文件,在原本基础上追加
        encoding 文件的编码形式
    print('hello file',file=open('./hello.txt','w',encoding='utf-8'))
5. flush  冲洗刷新的意思  

变量与数据类型

2.4.1变量

变量名词的定义来源于数学,和数学中方程式的变量是一样的,只不过在计算机中定义格式不一样,变量也不仅仅数字,还可以是其他格式的数据

使用某个标记名标记数据,这个标记名称为变量名

变量,从名字来进行判定,它标记的数据是可变化的

定义变量

在python中定义变量的格式变量名=数据值,这里的变量名起名的时候是要遵守一定的规则的,这个规则来源于标识符

变量定义的其他格式

  1. 同时定义多个变量名赋予相同的值

    【变量名1=变量名2=变量名3=数据值】

  2. 同时定义多个变量,但是值不相同

    【变量1,变量2=值1,值2】

注意:变量在使用之前一定要定义并被初始化【初始化就是给它赋予值,也就是不能职业一个变量但是没有给它赋值】

2.4.2标识符

计算机中自定义的名字称为标识符,比如子当以的项目名称,python文件名称、变量名、函数名、类名等的

规则:

  1. 可以包含数字,字母,下划线

    字母:注意python的编码格式是utf-8,这个是国际编码标准,收录的世界语言在内,这里的字母包含各国语言文字,换句话说各国语言文字统称为字母【英文。中文,德文….】起名字可以使用汉字,虽然各国语言都能进行定义,但是按照编写代码的规范建议还是使用英文

  2. 不能以数字开头

  3. 不能使用关键字与保留字

    • 关键字:在python中已经具有特殊含义的单词

    • 保留字:在Python中已经被使用定义的名字

      展示Python中的关键字

      被封装在一个工具库keyword

      怎么使用工具库

      ​ 因为Python环境中提供很多工具库 要想使用的话需要导入 导入到程序中

      如何进行导入?

      ​ import 工具库名称

      导入之后如何使用工具库下面的内容?

      ​ 工具库名称.内容名

不同内容的命名规范

  1. 项目名称在满足标识符基础的基础上,定义的时候建议采用打驼峰命名格式【每个单词首字母大写,比如PythonProject
  2. Python文件名称/变量名/函数名在满足标识符挥着的基础上,定义的时候英文字母都是小写的,单词和单词之间是用下划线隔开【比如max_value
  3. 尽量做到见名知意

2.4.3数据类型

计算机中能赫胥黎的数据不仅仅只有数字,还可以处理文本、图形、音频、视频、网页等等各种各样的数据,再做处理的时候按照数据的特征进行了归类

在Python中基本的数据类型有:

  1. 整形(int)

    整数类型,该类型的数据值全部都是整数,Python可以处理任意大小的整数【包括负整数在内】,写法和数学的格式是一样的,比如10 ,-20,100等等

  2. 浮点型(float)

    小数类型,智叟一叫浮点类型,是因为数字可以使用科学计数法表示,小数点是可以移动的,比如1.23*10^9 = 1.23e9 12.3e8

  3. 布尔类型(bool

    布尔值与布尔代数的表达形式是一样的,布尔值只有两个TrueFalse,这个值一般是来表达表达式运行结果的

  4. 字符串类型(str

    表达的是文本数据,是有单引号或者双引号包含起来的任意文本

    注意'0'0不是一个内容,前者是一个字符转,是一个文本,后者是一个数字,可以算术运算

    提这个的愿意你是在ASCII码中看到字符0对应的十进制数据是48,这个字符0是0,不是0

    在内存中存储的时候

    '0'===>48===>11 0000
     0 ===>00000000
    
  5. 空类型(NoneType

    有一个值就是None,这个表示的是空值【可以理解成空,什么都没有】

获取数据的类型方式type()

Python属于动态类型的语言,变量的类型由值来决定

​ 例如 num = 10 num为整形

num = 10.1 num为浮点型

f = ‘哈哈哈’ f为字符串类型

b = True b为布尔类型

数据太大时为了方便观察,可以使用下划线将数据分割

​ 12=1_2

字符串是一个有序的不可变的容器型数据

​ 字符串是由0个或者多个字符组合而成的,容器里面的数据元素就是字符

​ 字符:长度为1的字符串就叫做字符

当字符串是一对空引号,称之为空字符串【容器中什么符号都没有】

​ 空字符串不等于空值None

​ 把容器理解成箱子

'abc' 箱子中由数据a 数据b 数据 c

​ ‘’ 一个空箱子

​ None 就是连箱子都没有

2.4.4类型转换

在有些长江下需要把数据设置为相同类型的才能进行计算,这个就需要类型转换

  1. 把数据转化为整形,格式int(数据)int还有另外一个功能:把其他进制格式的字符转数据转化为十进制格式的整数要求:解读数据的时候 数据时几进制的 就得按照几进制及逆行解读

    int(其他进制的字符串数据,base=2)

    1. 对浮点数取整
    2. 把字符串转化为整型

    把整形数据转化为二进制

    bin(整形数据)

    把整形数据转化为八进制

    oct(整型数据)

    把整形数据转化为十六进制

    hex(整型数据)

    获取字符对应的十进制数据【按照编码规则UTF-8】

    ord(’字符‘)

    按照编码规则获取十进制数据对应的字符

    chr(数字)

    2.把数据转化为浮点型

    float(数据)

    做一个计算器,两个人一数字的差

    num1=float(input('请输入第一个数字:'))
    num2=float(input('请输入第二个数字:'))
    print(num1-num2)
    
    1. 把数据转化为布尔类型,格式

      bool(数据)

      规则:

       1. **数字格式的数据,非0即为True**
       2. **容器型数据,非空容器即为True**
       3. **None空值为False**
      

      这个规则要记住!!!因为后面的知识点中由逻辑判断

2.4.5容器数据类型

字符串

​ 概念及特点

​ 包含0个或多个字符的有序不可变的序列

​ 特点:有序性:添加顺序和显示顺序一致,添加字符的时候,会设置编号,编号是从0开始的,被称为索引、下标、脚标

​ 不可变性:在内存地址不变的情况下,字符串的内容不允许发生变化

​ 如果字符串的内容变了,内存地址就一定变了

定义字符串
  1. 使用引号包含【一对单引号 一对双引号 一堆三引号 预编译文本 保持内容的原样输出】

    s=’’ #空字符

定义字符串的索引和切片
s='12345'
print(s[0]) #获取第一个数据
print(s[4]) print(s[-1])#获取最后一个值
切片

操作 字符串[起始索引:结束索引:步长]

切牌你根据索引定位发那位,获取范围中的字串

根据步长的正负性,分两种

‘abcdef’

正向切片

​ 从左向右获取

​ 步长为正

​ 要求:起始索引定位的字符 在结束索引定位字符的左边

负向索引

​ 从右向左获取

​ 步长为正

​ 要求:起始索引定位的字符 在结束索引定位字符的左边

遍历字符串
  • 直接遍历字符串

    import string
    s='HsjkjhaklHJKASDFHjk(*)&5623kl'
    print(string.ascii_uppercase)#获取所有大写字母
    print(string.ascii_lowercase)#获取所有小写字母
    print(string.ascii_letters)#获取所有字母
    print(string.digits)#获取所有数字
    count=0
    for i in s:#直接遍历字符串
        if i in string.ascii_uppercase:
            count+=1
    print(count)
            
    
  • 遍历索引【应用场景:条件胡哦这结论中和索引相关】

    #应用场景 条件或者结论和索引相关
    #获取 大写的英文字母对应的索引
    for i in range(0,len(s)):
        if s[i] in string.ascii_uppercase:
            print(s[i],i)
    #获取 能被3整除  或者索引能被4整除 对应的字符
    for i in rang(0,len(s)):
        if i%3==0 or i%4==0:
            print(s[i])
    
  • 枚举遍历【这种最好用】

    #枚举遍历
    s='HsjkjhaklHJKASDFHjk(*)&5623kl'
    for i,j in enumerate(s):
        print(i,j)
    '''
    10 J
    11 K
    12 A
    13 S
    14 D
    15 F
    16 H
    17 j
    18 k
    19 (
    20 *
    21 )
    22 &
    23 5
    24 6
    25 2
    26 3
    27 k
    28 l
    '''
    for i,j in enumertate(s):
        if i%3==0 or i%4=0:
            print(j)
    
字符串的操作
字符串对象.find(字串,起始索引,结束索引)   不包含结束位置
    #启示和结束不给,默认在整个字符串中查找 如果只给起始 不给结束,默认从起始位置到最后查找
    #如果找到 返回的是第一次的索引位置【正向的】如果找不到 返回 -1
字符串对象.rfind(字串,起始索引,结束索引)   不包含结束位置
    #如果找到 返回的是最后一次的索引位置【正向的】如果找不到 返回 -1
字符串对象.index(字串,起始索引,结束索引)  不包含结束位置
    #如果找不到,报错
字符串对象.rindex(字串,起始索引,结束索引)  不包含结束位置
    #如果找不到,报错
s='abcabcabc'
print(s.find('abc'))
print(s.find('abc',1))
print(s.find('abc',1,6))
print(s.find('abc',1,5))
#index找不到报错
print(s.index('abc',1,5))

3获取某个字串在字符串中出现的次数
s='abcabcabc'
print(s.count('abc'))
#输出为3
s='ababababab'
print(s.count('abab'))
输出为2   #count记的是不重叠的

# 1. 判断字符串是否纯数字组成   字符串对象.isdigit()
s1 = '123'
s2 = '123a'
print(s1.isdigit())   # True
print(s2.isdigit())   # False
# -------------------------------------------------------------

# 2. 判断是否纯字母组成     字符串对象.isalpha()    注意:字母不仅指英文字母
s1 = '你好'
s2 ='abc1'
print(s1.isalpha())   # True
print(s2.isalpha())   # False
# -------------------------------------------------------------

# 3. 判断是否数字或字母组成   字符串对象.isalnum()   注意:字母不仅指英文字母
# 结果为True  有三种情况   纯数字   纯字母   数字+字母
s1 = '你好'
s2 ='abc1'
s3 = '123'
print(s1.isalnum())
print(s2.isalnum())
print(s3.isalnum())

# 1. 将小写英文字母转化为大写 其他不变  字符串对象.upper()
s = 'How aRe yOu'
print(s.upper())  # HOW ARE YOU

# ---------------------------------------------------
# 2. 将大写英文字母转化为小写  其他不变  字符串对象.lower()
print(s.lower())  # how are you
# ---------------------------------------------------

# 3. 将大写英文字母转化为小写  将小写英文字母转化为大写  其他不变  字符串对象.swapcase()
print(s.swapcase())  # hOW ArE YoU
# ---------------------------------------------------

# 4. 将字符串的首字母大写 同时 将其他英文字母小写 其他不变   字符串对象.capitalize()
print(s.capitalize())   # How are you
# ---------------------------------------------------

# 5. 将字符串中每个单词的首字母大写 其他英文字母小写 其他不变  字符串对象.title()
print(s.title())   # How Are You

# 1. 判断字符串是否纯数字组成   字符串对象.isdigit()
s1 = '123'
s2 = '123a'
print(s1.isdigit())   # True
print(s2.isdigit())   # False
# -------------------------------------------------------------

# 2. 判断是否纯字母组成     字符串对象.isalpha()    注意:字母不仅指英文字母
s1 = '你好'
s2 ='abc1'
print(s1.isalpha())   # True
print(s2.isalpha())   # False
# -------------------------------------------------------------

# 3. 判断是否数字或字母组成   字符串对象.isalnum()   注意:字母不仅指英文字母
# 结果为True  有三种情况   纯数字   纯字母   数字+字母
s1 = '你好'
s2 ='abc1'
s3 = '123'
print(s1.isalnum())   # True
print(s2.isalnum())   # True
print(s3.isalnum())   # True
# -------------------------------------------------------------

# 4. 判断字符串中的英文字母是否都是大写  字符串对象.isupper()
s = '你好123ABC'
print(s.isupper())  # True
# -------------------------------------------------------------

# 5. 判断字符串中的英文字母是否都是小写   字符串对象.islower()
s = 'abc123$%^&'
print(s.islower())  # True
# -------------------------------------------------------------

# 6. 判断字符串中的字符是否都是ascii码中的符号  字符串对象.isascii()
s = 'ADBGbh12你'
print(s.isascii())  # False
# -------------------------------------------------------------

# 7. 判断字符串中是否每个单词的首字母大写 其他英文字母小写  字符串对象.istitle()
s = 'HoW Are You'
print(s.istitle())

# 8. 判断字符串是否以指定内容开头     字符串对象.startswith(指定内容)
s = 'HoW Are You'
print(s.startswith('H'))
print(s.startswith('Ho'))
print(s.startswith('How'))

# 9. 判断字符串是否以多个内容中的其中一个开头    字符串对象.startswith((内容1,内容2,内容3)) 注意:序列
s = ' Are You'
print(s.startswith(('Ho', 'oW', 'W ')))
# -------------------------------------------------------------

# 10 判断字符串是否以指定内容结尾    字符串对象.endswith(指定内容)
s = 'HoW Are You'
print(s.endswith('u'))
print(s.endswith('ou'))

# 11. 判断字符串是否以多个内容中的其中一个结尾    字符串对象.endswith((内容1,内容2,内容3))  注意:序列
s = 'HoW Are '
print(s.endswith(('ou', 'Yo', ' Y')))、

# 编码方式
# gbk    汉字的编码  占2个字节
# utf-8  汉字 占3个字节

# 1. 字符串的编码  -- 字符串对象.encode(编码方式)
s = '你好'
utf_s = s.encode('utf-8')
print(utf_s)   # b'\xe4\xbd\xa0\xe5\xa5\xbd'
gbk_s = s.encode('gbk')
print(gbk_s)   # b'\xc4\xe3\xba\xc3'

# 2. 字符串的解码  --- 字节串对象.decode(解码方式)'
# 注意: 用什么方式 就用什么方式解码  否则的话  会乱码或报错

print(utf_s.decode('utf-8'))
print(utf_s.decode('gbk'))   # 浣犲ソ

print(gbk_s.decode('gbk'))
# print(gbk_s.decode('utf-8'))  # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte

# 特点:  ascii中的符号  编码前后 内容不变
print('abc1234ASHL'.encode('gbk'))
print('abc1234ABF'.encode('utf-8'))

# 判断操作
# 判断是否纯字母组成    isalpha()
# 判断是否数字或字母   isalnum()
# 字母不仅指英文
# -------------------------------------------------------
# 编码和解码
# ascii中的内容 编码前后 不变的
# 中文  编码  字节数据   '\x5e\xbd\xe5\xfc' --  \
# 十六进制  0123456789 abcdef -- 数字或英文字母   x -- 英文字母

# 判断字符串是否纯英文字母组成   -- 字符串.encode(编码方式).isalpha()
# 字符串对象.encode(编码方式).isalpha()    -- 纯英文字母
# ‘abcdef’.encode(编码方式) -- ‘abcdef’
# ‘你好’.encode() -- '\xac\xde\xe3' -- 是纯字母  \
s = '你好'
print(s.isalpha())
print(s.encode('gbk').isalpha())   # False

s = 'abcABC'
print(s.isalpha())
print(s.encode('utf-8').isalpha())

# 判断字符串是否为数字或英文字母   -- 字符串.encode().isalnum()
s = 'abc123'
print(s.encode('utf-8').isalnum())

# 判断 数字和字母组成  1.满足数字或字母  2.不是纯数字  3. 不是纯字母
# 数字或字母  纯数字  纯字母  数字+字母

s = '123b'
print(s.isalnum() and not (s.isdigit()) and not (s.isalpha()))

# 1. 字符串的切割
# 将字符串按照指定的切割符号,切割成几部分 最终的结果是列表
# 操作   字符串对象.split(切割符号,切割次数)
# 如果不指定次数 按照所有的切割符号全部切割   如果不指定切割符号 按照空白字符切割 【空白字符 != 空格】
s = 'how are you'
# 指定切割符号   如果按照切割符号全部切割  最终的结果中不含有切割符号
print(s.split(' '))  # ['how', 'are', 'you']
# 不指定切割符号
print(s.split())  # ['how', 'are', 'you']
# ------------------------------------------------------------------
# 空白字符    \n  \t  \r  \v  \f  空格
s = 'how\nare\tyou'
print(s.split(' '))  # ['how\nare\tyou']
print(s.split())  # ['how', 'are', 'you']

s = 'how  are  you'
# s.split(' ')  ['how','','are','','you']
print(s.split(' '))  # ['how', '', 'are', '', 'you']
print(s.split())  # ['how', 'are', 'you']
s = 'how are you'
# 指定切割次数 
print(s.split(' ', 1))  # ['how', 'are you']
# 从右边开始切割   全部切割 没有区别   只有指定的次数不全部切割 有区别
print(s.rsplit(' '))  # ['how', 'are', 'you']
print(s.rsplit(' ', 1))  # ['how are', 'you']
# ------------------------------------------------------------------------------------
# 2. 拼接   字符串中特殊的一个操作  拼接符号.join(序列)  序列有要求:要求每一个元素是字符串类型
# 形成的结果 是将序列中的多部分 拼成一个字符串
l = ['how', 'are', 'you']
print(' '.join(l))  # 'how are you'
print('+'.join(l))  # how+are+you
l = ['1', '2', '3']
print('+'.join(l))  # 1+2+3
# 1.替换  将字符串中的指定内容 替换成 新内容
# 字符串对象.replace(旧内容,新内容,替换次数)
# 如果替换次数不指定  全部替换
s = 'how are you'
# 需求  将s中的空格去掉   把空格 替换成 空字符串
print(s.replace(' ', ''))  # howareyou
print(s.replace(' ', '', 1))  # howare you
# ------------------------------------------------------------
# 2. 去除  去除字符串两端的指定内容
# 字符串对象.strip(指定内容)  指定内容可以不给,如果不给,表示去除字符串两端的空白字符
s = ' \n  a b c  \t '
print(s.strip(' \n\t'))
print(s.strip())
# 单独去除左边的  字符串对象.lstrip(指定内容)
# 单独去除右边的  字符串对象.rstrip(指定内容)
print('---------------------------------------------------------------')
s = ' \n  a b c  \t '
print(s.lstrip('\n '))
print('--------------------------')
print(s.rstrip(' \t'))
print(s.rstrip())

3获取某个字串在字符串中出现的次数
s='abcabcabc'
print(s.count('abc'))

输出为3

s='ababababab'
print(s.count('abab'))
输出为2 #count记的是不重叠的

将小写英文字母转化为大写

s='How aRe You'

print(s.upper())

将大写英文字母转化为小写

s='How aRe You'

print(s.lower())
转义字符

防止转义的方法:

  1. 使用\表示\

    print('\\user\\aiaiai')
    
  2. 使用R修饰

    print(R'\user\aiaiai')
    
列表
概念及特点
  • 列表的标识是[],存储零个或者多个元素的有序可变序列,列表中的元素可以是u洞中数据类型,但是为了数据的统一性,经常会使用同一种数据类型
  • 特点
    • 有序 添加顺序和显示顺序一致,编号从0驾驶 就是索引
      • 可以通过索引获取对应的元素 体现就是有索引 有切片
    • 可变
      • 内存地址不变的情况下,数据可以发生变化 【增加 删除 修改】
定义列表
  • 使用[]包含

    # 定义
    # 1. 使用[]包含   2. list()
    # 空列表
    l = []
    l1 = list()
    print(l, type(l), len(l))
    print(l1, type(l1), len(l1))
    l = []
    print(l, len(l))
    # 非空列表
    l = [1, 2, 3, 4]
    print(l, type(l), len(l))   # [1, 2, 3, 4] <class 'list'> 4
    
  • 使用list()构造

    # 可遍历数据   字符   range()
    # l = list(10)  # list(数据不能乱写  序列)
    # print(l)   # 'int' object is not iterable   可遍历的
    l = list('abc')
    print(l) # 字符串的每一个字符 作为一个元素 放在列表中  ['a','b','c']
    print(range(10))   #  range(0, 10)
    l = list(range(10))
    print(l)        # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    列表的索引和切片(字符串不可以拿出修改,但是列表可以)

    l = [1, 2, 3, 4, 5, 6]
    print(l[0])
    print(l[-1])
    print(l[:3])
    print(l[-3:])
    print(l[3::-1])
    print(l[:])
    print(l[::-1])
    
    # 区别  列表是可变的  修改值 -- 获取再重新赋值
    # 修改列表中的第一个元素 100
    print(l, id(l))
    l[0] = 100
    print(l, id(l))  # [100, 2, 3, 4, 5, 6]
    # 修改最后一个元素  600
    l[-1] = 600
    print(l, id(l))  # [100, 2, 3, 4, 5, 600]
    
    # s = 'abc'
    # s[0] = 'A'
    # print(s)
    
    # 可以修改切片
    l = [1, 2, 3, 4, 5, 6, 7]
    # 获取再重新赋值
    # 获取的切片 数据如果连续  赋值的时候 赋值的个数可以是任意个
    l[:3] = [10, 20, 30, 40, 50, 60, 70, 80]
    print(l)
    
    # 如果获取的切片不连续  赋值的时候 要求 赋值个数与获取元素个数一致
    l = [1, 2, 3, 4, 5, 6, 7]
    print(l[::3])
    l[::3] = [10,20,30]
    print(l)
    
    
符号 含义
+ 合并两个列表中的数据(将两个列表中的数据组合成一个新的列表)
* 将列表中的数据重复
+= 在当前列表的基础上【内存地址不变】,合并序列
*= 在当前列表的基础上【内存地址不变】,将列表中的数据重复
# +  合并列表
l1 = [1, 2, 3]
l2 = [4, 5, 6]
l3 = (7, 8, 9)
print(l1 + l2)  # [1, 2, 3, 4, 5, 6]
# print(l1 + l3)  # TypeError: can only concatenate list (not "tuple") to list

# *  列表中的内容重复
print(l1 * 3)  # [1, 2, 3, 1, 2, 3, 1, 2, 3]

# +=  在当前列表的基础上 合并序列   1. 当前列表的基础上【内存地址不变】   2. 序列
l1 = [1, 2, 3]
print(l1, id(l1))
l1 += [4, 5, 6]
print(l1, id(l1))
l1 += (7, 8, 9)
print(l1, id(l1))
l1 += range(10, 12)
print(l1, id(l1))
l1 += 'abc'
print(l1, id(l1))
# s = 'abc'
# print(s,id(s))
# s+='d'
# print(s,id(s))

# *=
l1 = [1, 2, 3]
print(l1, id(l1))
l1 *= 3
print(l1, id(l1))
# 比较运算符
l1 = [1, 2, 3]
l2 = [1, 3, 2]
print(l1 > l2)  # False

l1 = [2]
l2 = [1, 10, 10, 10, 10, 10, 10, 10]
print(l1 > l2)  # True

# l1 = [1,2,3]
# l2 = ['a','b','c']
# print(l1 > l2)

l1 = ['abc', 'def']
l2 = ['d']
print(l1 > l2)  # False

# 成员
l = ['1', 2, 3, 4, 5]
print('1' in l)

#
l = ['abc', 'def']
print('a' in l)
列表的操作
# 增加元素
l = [1, 2, 3]
print(l, id(l))
# 1. 追加元素  列表.append(元素)  添加的元素在列表的最后
l.append(4)
print(l, id(l))  # [1, 2, 3, 4]
# 2. 指定位置添加   插队   列表.insert(索引,元素)    将原有索引位置及以后的元素整体向后移动一位
l.insert(1, 10)  # 索引1的位置 插入元素10
print(l, id(l))  # [1, 10, 2, 3, 4]
# 3. 合并序列 等同于   +=
l.extend([1, 3, 5, 7])
print(l, id(l))
l.extend(range(8, 10))
print(l, id(l))
l.extend((4, 5, 6))
print(l, id(l))
l.extend('abc')
print(l, id(l))

# 注意----------------------------------------
# l1 = [1, 2, 3]
# l1.append([4, 5, 6])
# print(l1)  # [1,2,3,[4,5,6]]
# l1 = [1,2,3]
# l1.extend([4,5,6])
# print(l1)  # [1, 2, 3, 4, 5, 6]
# --------------------------------------------

# 删除元素
# 1. 删除列表中的最后一个元素  列表.pop()
l.pop()
print(l, id(l))
l.pop()
print(l, id(l))
# 2. 删除指定索引位置的元素   列表.pop(索引)
l.pop(0)
print(l, id(l))
# 3. 删除指定的元素  根据元素的值删   列表.remove(元素)
# 如果元素在列表中有多个  删除找到的第一个   如果元素在列表中没有  报错
l.remove(3)
print(l, id(l))
# l.remove(100)
# print(l,id(l))   # ValueError: list.remove(x): x not in list
# 4. 清空  将列表中的所有元素都删除  列表.clear()
# l.clear()
# print(l,id(l))

# 修改元素 --- 讲过了

# 获取的操作
# 1. 获取某个元素第一次出现的位置    列表.index(元素,起始索引,结束索引)
l = [1, 2, 3, 4, 1, 1, 1]
print(l.index(1))  # 0
# print(l.index(100))  # ValueError: 100 is not in list
# 2. 获取某个元素出现的次数   列表.count(元素)
print(l.count(1))
print(l.count(100))

# 其他操作
# 1. 复制  切片 列表[:]      列表.copy()
print(l.copy())  # [1, 2, 3, 4, 1, 1, 1]

# 2. 反转  切片 列表[::-1] 产生一个新列表 不修改原有列表   列表.reverse()  修改原列表
l = [1, 2, 3, 4]
print(l[::-1])
print(l)

l = [1, 2, 3, 4]
l.reverse()
print(l)

# 3. 排序  将列表中的数据进行排序   升序 降序   直接修改的是原列表
# 列表.sort()  默认是升序排序  如果想降序排序 列表.sort(reverse=True)
l = [4,1,2,3]
l.sort()
print(l)

l.sort(reverse=True)
print(l)

列表的易错点

元组

######元组的定义 特点 索引和切片

# 定义
# 1. ()  提升优先级()   2.tuple()构造
# 空元组
# 1. ()
t = ()
print(t,type(t),len(t))
t = tuple()
print(t,type(t),len(t))
# 非空元组
# 特殊点 如果元组中只有一个元素   (元素,)
t = (10,)
print(t,type(t))

# t = tuple(10) # 可迭代数据   'int' object is not iterable

t = tuple('abc')
print(t)   # ('a', 'b', 'c')
t = tuple([1,2,3])
print(t)  # (1, 2, 3)
t = tuple(range(10))
print(t)

元组支持的运算符
# + 合并元组   元组 + 元组    列表 + 列表            不能支持 列表 + 元组
t1 = (1, 2, 3)
t2 = (4, 5, 6)
l = [7, 8, 9]
print(t1 + t2)
# print(t1 + l)

# *  重复
print(t1 * 3)  # (1, 2, 3, 1, 2, 3, 1, 2, 3)

# +=  产生新元组  只能合并元组
t1 = (1, 2, 3)
t2 = (4, 5, 6)
print(t1, id(t1))
t1 += t2
print(t1, id(t1))

# l = [7, 8, 9]
# t1  += l
# print(t1)

# *=  产生新元组
t1 = (1, 2, 3)
print(t1, id(t1))
t1 *= 3
print(t1, id(t1))

# 比较
t1 = (3, 2, 1)
t2 = (10, 1, 1)
print(t1 > t2)  # False

t1 = ('a', 'b', 'c')
t2 = ('d',)
print(t1 > t2)   # False

# 成员
t1 = ('ab', 'bc', 'ca')
print('ca' in t1)
字典
概念及特点
  • 字典的标识[],数据是键值对的形式,{key:value,key:value}
  • 存储零个或者多个键值对 无序可变序列
  • 无序:不存在索引,不能像有序序列一样,通过字典[索引]的方式进行获取,但是他的键相当于是有序序列的索引,所以对键有要求:
    1. 键不重复
    2. 键要求是不可变类型的数据。可以做键的类型:【字符串、元组、整形、浮点、布尔】
  • 可变性 内存地址不变的情况下,数据可以发生变化【增加键值对 删除键值对 修改某个键对应的值】
定义字典
  • 使用{}包含
  • 使用dict构造
# 定义
# 1. {}   2.dict()
# 空字典
d = {}
print(d, type(d), len(d))  # {} <class 'dict'> 0
d = dict()
print(d, type(d), len(d))
# 非空字典
d = {'数学': 80, '语文': 90}
print(d, type(d), len(d))
d = {'a': 10, 'b': 20}
print(d, type(d))
# dict()   键  值  构造字典  有键 有值
# 1. 传入的数据  二维数据   [(键,值),(键,值),(键,值)]
data = [('数学',100),('语文',90),('英语',80)]
d = dict(data)
print(d,type(d))
# 2. 变量名=值    变量名 【不加引号】
d= dict(数学=100,语文=88,英语=46)
print(d,type(d))
字典支持的运算符

装包和解包

# 装包
# 把多个值赋值给一个变量  把多个值打包成一个元组 赋值给这个变量 这个过程就是装包
a = 10, 20, 30
print(a, type(a))  # (10, 20, 30) <class 'tuple'>

# 拆包
# 多个变量 接受一个序列  将序列解包  这个过程就是拆包
a, b, c = (1, 2, 3)
print(a, b, c)
a, b = [10, 20]
print(a, b)

# 1. 变量 < 序列中的元素数  可以解决   让某一个变量   接受多个值
# a,b = (10,20,30)
# print(a,b)   # ValueError: too many values to unpack (expected 2)
# 处理方式  给某个变量前面 *,被*修饰的变量 可以接受多个值
*a, b, c = (10, 20, 30, 40, 50, 60)
print(a, b, c)  # [10, 20, 30, 40] 50 60

a, *b, c = (10, 20, 30, 40, 50, 60)
print(a, b, c)  # 10 [20, 30, 40, 50] 60

a, b, *c = (10, 20, 30, 40, 50, 60)
print(a, b, c)  # 10 20 [30, 40, 50, 60]

# 2. 变量 > 序列中的元素数
# a,b,c,d = (10,20,30)
# print(a,b,c,d)   # ValueError: not enough values to unpack (expected 4, got 3)

t = [1,2,3]
for pos,ele in enumerate(t):
    print(pos,ele)

字典的操作
# 字典可变   增加  删除  修改  获取
d = dict(数学=100, 语文=90)
print(d, type(d), id(d))
# 1. 增加键值对
# 字典对象[键] = 值     1. 如果键不存在,添加键值对  2. 如果键存在,修改原有字典中键对应的值
d['体育'] = 66
print(d, id(d))  # {'数学': 100, '语文': 90, '体育': 66}
d['数学'] = 99
print(d, id(d))
# 添加键值对   字典对象.setdefault(键,值)   # 1. 键不存在 添加键值对  2. 键存在  不做反应
d.setdefault('英语', 88)
print(d, id(d))
d.setdefault('数学', 70)
print(d, id(d))
# 合并序列   合并  字典  二维数据  变量名=值   字典对象.update(序列)
d1 = {'物理': 56, '化学': 48}
d.update(d1)
print(d, id(d))
d.update([('生物', 77), ('地理', 96)])
print(d, id(d))
d.update(美术=69, 音乐=79)
print(d, id(d))

# 2. 删除键值对   键--有序序列的索引  键来进行定位键值对  根据键删除
# del 字典对象[键]
del d['体育']
print(d, id(d))

# 字典对象.pop(键)
d.pop('美术')
print(d, id(d))

# 清空  字典.clear()
# d.clear()
# print(d,id(d))

# 3. 修改  修改某个键对应的值    字典对象[键] = 值

# 4. 获取的操作
# 获取某个键对应的值      字典对象[键]   1. 键存在,获取对应的值  2. 键不存在 报错
print(d['地理'])
# print(d['物理1'])  # KeyError: '物理1'
# 获取某个键对应的值   字典对象.get(键)  1. 键存在,获取对应的值  2. 键不存在 返回 None  支持自定义返回值
print(d.get('地理'))
print(d.get('物理1'))  # None
# 自定义返回值   字典对象.get(键,自定义的值)
print(d.get('物理1', 0))
# 获取字典中所有 的键  key:value  字典对象.keys()
print(d.keys())
# 获取字典中所有 的值   字典对象.values()
print(d.values())
# 获取字典中所有的键值对   字典对象.items()
print(d.items())
集合
概念及特点
  • 数据标识{},啊存储多个确定且不重读额的无序可变序列
  • 特点
    • 无序性
    • 可变性
    • 唯一性
定义集合
  1. 使用{}包含,其中必须有数据
  2. 使用set{}构造,空集合必须用set{}构造
# 定义
# 1. {}   2. set()
# 空集合的构造
# s = {}
# print(s,type(s))

s = set()
print(s, type(s), len(s))  # set() <class 'set'> 0

# 非空集合
s = {1, 2, 3, 4}
print(s, type(s), len(s))
s = {1, 2, 3, 1, 1, 1, 1, 1, 1}
print(s, type(s), len(s))

s = set('abc')
print(s,type(s))
s = set([1,2,3,1,1,1])
print(s,type(s))

# 作用  去重
# 循环  获取字符串中不重复的字符 如果有多个 保留一个
s = 'aaabbbccc'
s1 = ''
for i in s:
    if i not in s1:
        s1 += i
print(s1)

s = 'aaabbbccc'
print(''.join(set(s)))
支持的运算符
  • 子集 子集是集合的部分或者是结合的全白
  • 真子集 只能是集合的一部分
加入有两个 集合 A和B
&  求集合的交集  集合A和集合B共有的部分
|  求集合的并集
^  求集合的对称差集   两个集合的所有 - 两个集合的公共部分
- 求两个集合的差集    A-B  A中不包含B的部分

比较运算符  [判断子集【可以是部分 可以是全部 >= <=】和真子集【只能是部分 >  <】] 
>    判断后面集合是否为前面集合的真子集 
>=   判断后面集合是否为前面集合的子集 
<    判断前面集合是否为后面集合的真子集 
<=   判断前面集合是否为后面集合的子集 
==   判断两个集合中元素是否相同的  和顺序无关 
!=

###2.5运算符

分为一元运算符、二元运算符、三元运算符【Python中没有直接的三元运算符】

2.5.1算数运算符

加法 +
减法 -
乘法 *
除法 /   结果是浮点类型的,除不尽 商会有小数
    //  结果是整形的,对商进行向下取整
取余数 %
求幂数 ** 比如 x**y  求x的y次方

算术运算符的优先级别

** > * / // % > + -

2.5.2赋值运算符

  1. 简单赋值运算符

    变量名 = 数据值
        将等号右边的表达式计算结果赋值给左边的变量名
        例如:
            a = 17
            a = 19 % 4
            b = 18
            a = b // 4
    
  2. 复合赋值运算符

    结合其他运算符在内的赋值格式
    变量名 += 表达式
    -=
    *=
    /=
    //=
    %=
    **=
    
  3. 赋值表达式(海象运算符)

    把某个赋值表达式的结果再赋值给另一个变量,这种格式称为赋值表达式

    比如在其他语言中 支持 y=(x = 17 % 3)

    解读: 先计算x的结果,再把x的值赋值给y

    但是这个写法Python在python中不支持,在python中的写法为: y = ( x := 17 % 3 )

    线性关系

    x=int(input('请输入x的值'))
    y=2*x+5
    
    可以写为
    
    y=2*(x:=int(input('请输入x的值')))
    

2.5.3比较运算符

>
<
>=
<=
==
!=

算数运算符的优先级高于比较运算符

​ 介绍字符串数据的比较,本质比较的是字符对应的十进制数据,比较会这是相同位置的字符进行比较,知道比较出结果

比如
s1 = 'hello'
s2 = 'head'
res = s1 > s2 这个结果是真还是假?

第一次比较是 h 对 h
第二次比较是 e 对 e
第三次比较是 l 对 a  成立
因此结果为真

2.5.4逻辑运算符

逻辑运算符是用来关联表达式的逻辑关系的,逻辑关系是有三种的

(逻辑运算符的优先级别低于比较运算符)

  1. 逻辑与(and)

    连接的逻辑关系是一个并且的关系,这两个表达是同时成立,结果才是成立的

    True and True = True
    True and False = False
    False and True = False
    False and False = False
    

    总结and的运行机制:

    and是具备有短路原则,左边表达式不成立,右边表达式不被执行

  2. 逻辑或(or)

    连接的逻辑关系是或者的关系,两个表达式中有一个成立,结果就是成立的

    True or True = True
    True or Flase = True
    False or True = True
    False or False = False
    

    or也是具有短路原则的,当左边第一个为True时,结果直接为True

  3. 逻辑非(not)

    对逻辑府岸西取反,逻辑府岸西结果为真,not之后设定为假;逻辑结果为假,not之后设定为真

优先级别问题:

not > and > or

2.5.5成员运算符

成啊元你运算符是用来判定 数据是否某个容器型数据中的元素

数据 in 容器型数据
    把数据作为一个整体 判断是否在在容器中
数据 not in 容器型数据
    把数据作为一个整体,判断数据是否在容器中
    

2.5

判定两个数据的地址在内存中是否是一致的

数据1 is 数据2

启动程序,维护程序运行的数据存储于内存中,当程序结束后,内存被释放

内存也是分为不同区域的,不同的区域存储的数据是不一样的,数据的生命周期也是不一样的,区域有

  1. 栈区

  2. 堆区

  3. 常量池

    常量池中存储的是数值类型以及字符串类型的数据

    特点:获取数据时检查数据是否在常量池中存在,如果存在的话直接根据地址获取数据,如果啊不存在,先分配空间添加数据,再把数据的地址赋值给变量

    生命周期:当成程序结束的时候才会释放
    常量池中的数据有:

        1.小整数:
            [-5,256]
        2.布尔值
        3.None值
        4.不包含特殊符号的字符串
    
  4. 静态池
    存储全局变量【直接在py文件中定义的变量称为全局变量】
    生命周期:当程序结束的时候才会释放

  5. 方法区

2.5.7位运算符

& 按位与
    相同位置的数据,只要有一个是0,该位置的结果是0
| 按位或
    相同位置的数据,只要有一个是1,该位置的结果是1
^ 按位异或
    相同位置的数据一样,为0,数据不同为1
    一个数与相同的数异或两次结果是其本身
    【交换两个变量的值】
        方式一
            c=a
            a=b
            b=c
        方式二 采用异或
            a=a^b
            b=a^b
            a=a^b
        方式3 采用距离问题
            a=a+b
            b=a-b
            a=a-b
        方式4 python独有的方法
        a,b = b,a
~ 按位取反
    该位置上的数据0变1,1变0
>>按位右移
    将二进制数据向右移动N位,左边空出
    如果是整数,左边补零
    如果是负数,左边补一
<<按位左移
    将二进制数据向左移动N位,右边空出补0

位运算符都是针对于位【二进制数据中一个0或者一个1称为一位】

在计算机发展过程中,根据数据计算的发展的一个历程,二进制形态出现过三种:原码、反码、补码。现在的计算机中存储处理二进制数据的形态是补码

​ 对于正数来说三码合一,格式是一样的,样子就是将数据转化位二进制的格式

​ 负数的原码:在正数的基础上将最高位置为1,则表示这个数据为负数【二进制的最高位为符号位:0表示正数 1表示负数】,之前接触过进制转换,数据大小不一样,获取的二进制数据中位的个数不一样,怎么确定哪个是最高位???【计算机中数据存储时开辟的最小单元十字街,1个字节是8位,位数以确定 最高位就确定了】,比如常规的数据开启的字节数是4个字节

​ 负数的反码:在负数原码的基础上,出了符号位,0变1,1变0

​ 负数的补码:在负数反码的基础上加1

2.6流程控制语句

2.6.1顺序结构语句

代码是从上向下逐行运行的

2.6.2分支结构语句

分为三种格式

  1. 单分支

    语法:

    if 条件表达式:
        满足条件执行的代码块
    

    语境:如果达到了某个条件,就去做某件事

    :缩进 代表Python中的代码块的包涵体,满足要求执行的代码要统一缩进体现出来包含的关系f

  2. 双分支

    语法:

    if 条件表达式:
        满足条件执行的代码块
    else:
        不满足条件执行的代码块
    

    语境:啊如果满足某个条件做事情A,否则做事情B

  3. 多分支

    语法:

    if 条件表达式1:
        满足条件1执行的代码块
    elif 条件表达式2:
        满足条件表达式2不满足条件表达式1执行的代码块
    elif 条件表达式3
        满足条件表达式3不满足条件表达式1和2的代码块
    else
        以上条件都不满足执行的代码块
    

    语境:如果满足条件1,就做事情A,如果满足条件2,就做事情B,都不满足,就做事情C

语句嵌套

在满足某种要求的基础上,还需要进行逻辑判断才可以运行

python中的三元运算符

格式

​ 表达式1 if 条件表达式 else 表达式2

​ 解读:如果条件表达式成立 执行表达式1 不成立执行表达式2

隐式布尔转换

隐式:把非布尔类型的数据当作布尔类型判定逻辑,这种行为称为隐式布尔类型转换

​	非布尔类型的数据参与逻辑的运算的时候 和布尔类型的数据参与逻辑运算是不一样的

​	因为布尔类型的值只有两个 True或者False  参与逻辑运算结果也就只有两个,要么为True 要么没False

​	但是非布尔类型的数据 ,因为有一个隐式转换规则  结果又取的是表达式的  这个结果不一定是True或者False
非布尔类型的数据,在参与逻辑运算的时候,先通过转换规则隐式转换为True或者False,但是其数据本身并没有发生改变,只是取了其对应的布尔值
res = 1 or 0
print(res)

2.6.3循环结构语句

循环:周而复始的做某件事

编程语言中对一直从父做某件事没有种植的情况称为死循环,但是编程语言中是进制死循环

在编程语言中见到的循环通常是两种情况:

  1. 明确循环次数
  2. 明确循环结束的条件

Python为这两个场景的循环提供了对应的循环机制,分别是

  1. for-in循环,应用于明确循环次数的

    本质在遍历容器型的数据,【遍历:将容器中的数据从左向右诸葛取出】,容器中有几个数据,for-in包含的操作就被执行几次

    for 变量名 in 容器型数据:
        重复操作的代码块
    

    解读:重点在in【进入】,进入容器中获取数据

    1. 有数据,获取出来赋值给变量名,然后及逆行中重复操作,再次执行in
    2. 没有数据 循环结束
  2. while循环,应用于明确循环结束条件的

    语法:

    while 条件判断
        重复操作的代码块
    

    解读:判断条件是否成立

    1. 条件成立,执行重复的操作,再次判断条件是否成立
    2. 条件成立,循环结束

range功能

用来产生等差数列,这个结果也是通容器类型的一个数据,是range类型的

注意:range只能产生证书的等差数列

格式1: range(stop结束值)
        序列中的数值是从0开始步长为1的递增到stop[不包含]的数列
        比如 range(10) ===> 0 1 2 3 4 5 6 7 8 9 
格式2: range(start起始值, stop结束值)
        序列中的数值是从start[包含]开始步长为1的递增到stop[不包含]的数列
        比如: range(1, 11) ===> 1 2 3 4 5 6 7 8 9 10
格式3:range(start起始值, stop结束值, step步长)
        step为正数 表示递增的数列  start < stop
        step为负数 表示递减的数列  start > stop
        从start[包含]开始 以步长 step 递增或者递减到 stop[不包含]的数列
        比如: range(1, 11, 2) ===> 1 3 5 7 9 
        range(1, 100, 10) ====> 1 11 21 31 41 51 61 71 81 91  [可以理解为100以内 个位数为1的数据]
        range(10, 0, -2) ====> 10 8 6 4 2 
        

break、continue、pass

pass是代码块占位符,代码块中不能空白,【那块的逻辑暂时未写,可以使用pass占位】

  1. break 的作用是退出结束其所在的循环语句
  2. continue 的作用是结束当前执行,回归到条件判断或者in遍历操作的位置,检测调价你是否成立过着容器是狗还有数据,条件成立或者是容器中有数据,继续执行下一次,否则结束循环

有笔记未完成


2.7.2函数的参数

位置参数

def add(a,b)

这个的a和b就是位置参数,也成为必须参数,调用函数的时候必须给这些参数赋值,赋值的顺序和参数的顺序必须一致,并且个数也应该一致

默认参数

定义函数的时候,有些参数已经被赋予了数据值,这种参数就成为默认参数

特点:不给它赋值,使用默认值参与运算,赋值的话使用新值进行运算

print 也是函数,但是不是我们自己定义的,而是系统中自带的

注意:默认参数的定义必须在非默认参数之后

关键字参数

可变参数

  1. *args

2.7.3递归算法

算法:前辈们总结出来的解决某种问题的方法

递归:函数自己内部调用自己的的结构,递归式循环的另外一种表达形式
能形成递归代码的都是有规律的,看可以找大规律,把规律映射成函数

斐波那契数列:求第N个月的兔子的对数

  1. 写递归的时候一定要有已知项【代表了递归的出口】没有这个已知项,相当于写了一个死循环
  2. 递归的层次不能太深【递归就是在重复的调用自己 就是一个循环 可能会造成程序卡顿 或者 程序崩溃 递归占用内存资源】

2.7.4函数嵌套

def outer():
    def inner():
        print('你好')

两个关键字:

  1. global

    对函数内部的变量进行定义,使在函数内部可以修改全局变量

    age=10
    def outer():
        global age =20
    outer()
    print(age)
    #输出为20
    
  2. nolocal

    对嵌套的内部函数中的变量进行定义,使在内部函数内部可以修改外部函数的变量

    def outer():
        age=10
        def inner():
            nolocal age =20
        inner()
        print(age)
        #age=20
    

系统的内置函数

与数学相关的函数

  1. 1. 求幂数
    
       pow(2.5)  2**5
    
    2. 求绝对值
    
       abs(-100)
    
    3. 四舍五入  默认保留整数  
    
       round(11.5) # 12
    
       指定保留的小数位数
    
       round(19.725,1)  #保留一位小数
    
    4. 取整取余(默认返回结果是一个元组,里面有商和余数)
    
       divmod(10,3)  #(3,1)
    
    5. 求和sum  传入的数据必须是元组或者是列表
    
       sum([1,2,3,4]) #10
    
       sum((1,2,3,4)) #10
    
    6. 最大值 max
    
       max(1,2)  #2
    
    7. 最小值 min
    
       min(2,3) #2
    

    字符与十进制数据

    1. 将字符转化为十进制数据
       ord('你‘)
    2. 将十进制转化为字符
       chr(65)
    进制转换
    1. bin(100)  #将十进制转化为二进制
    
    2. oct(100)  #将十进制转化为八进制
    
    3. hex(100) #将十进制转化为十六进制
    
    4. int(4,8)    #将其他进制转化为十进制  两个参数(要转换的数,要转换的数的进制)
    
       例如int(4,8)就是将原本为八进制的4转化为十进制
       
    

    其他

    #判断某个数据是否为指定的数据类型
    isinstance(10,int)#True
    isinstance(10,(int,floa))#True  判断某个数据  是否为 某几个数据其中的其中一个
    #eval  解析字符串  和 str()相反的
    # str()类型转换  把其他类型的数据转化为字符串   原有数据的外层加一对引号
    #eval() 将引号去掉
    '1+2+3+4'
    print(eval('1+2+3+4'))
    #输出为1+2+3+4
    num = eval(input('请输入:'))
    print(type(num))
    #输入123  输出为 int
    #输入123.5输出为 float
    

    文件的读写操作

2.7.5lambda函数(匿名函数)

def get_sum(num1,num2):
    res=num1+num2

匿名函数 对简单功能函数封装 简单到不用其函数名

语法表达式:

​ lambda 参数1,参数2 :功能表达式

lambda num1,num2:num1+num2

匿名函数的主要应用场景 作为另一个函数的参数传递 高阶函数

例如:

​ 求一个数的个位数

f= lambda x:x%10
print(f(12))
#输出2

2.7.6高阶函数

高阶函数 作为另一个函数的参数的形式 A函数的某一个参数仍是一个函数

高阶函数的演化过程 重要理解的部分 作为参数的函数的作用位置

例如:求多个数制定规则下的最大值

# 把上面的三个函数 统一成一个函数
# 把求指定条件的最大值  条件封装成参数
# key 传递 求xxx最大   key = None  默认参数  默认参数可以不传值 如果不传值 求数值最大  如果传值  求指定条件下的最大  key的值其实就是一个函数的地址,方便我们在函数中调用需要的函数
def get_max0(l, key=None):
    max_value = l[0]
    for i in l:
        # 判断条件
        if key == None:
            # 要比较的两个值 就是 i和 max_value
            compare_ele, compare_max_value = i, max_value
        else:
            # 如果传值  要比较的两个数 是 被key作用过的值
            compare_ele, compare_max_value = key(i), key(max_value)
        # 比较
        if compare_ele > compare_max_value:
            max_value = i
    return max_value


print(get_max0([19, 28, 37, -46], key=abs))  # key
print(get_max0([19, 28, 37, -46], key=lambda x: x % 10))  # key  求一个数的个位数   key 作用于序列中的每一个元素
print(get_max0(['abc', 'a', 'd', 'aaaaa'], key=len))
print(get_max0(['abc', 'a', 'd', 'aaaaa'], key=lambda x: x[-1]))  # 最后一个字符最大   key 作用 获取序列中每一个元素的最后一个字符

系统内置高阶函数

# max(*args,key=None)
print(max([1, 2, 3, 4, 10, 5]))
print(max([1, 2, -5, 3, 4], key=abs))
print(max([19, 28, 37, 46], key=lambda x: x % 10))
# min(*args,key=None)
print(min('azzza', 'ad', 'zzzzza'))
print(min('azzza', 'ad', 'zzzzza', key=lambda x: x[-1]))

# 列表.sort()     默认是升序排序  如果想降序  列表.sort(reverse = True)
# l.sort(key=None,reverse=False)  key 指定排序方式的  reverse 指定 升序还是降序
# 列表.sort()  仅能对列表排序  并且 影响的是原列表
l = [10, 20, -30, 50]
# l.sort()
# print(l)
l.sort(key=abs)
print(l)
l = ['azzza', 'adaaaaaaaaaa', 'zzzzza']
# l.sort()
# print(l) 
# 按照长度降序排序
l.sort(key=len, reverse=True)
print(l)

# sorted()  排序操作  对任意序列排序  返回的结果是列表   产生的是一个新列表
# sorted(iterable,key,reverse)  iterable 指定排序序列的  key 指定排序规则  reverse 升序降序的
print(sorted(['azzza', 'adaaaaaaaaaa', 'zzzzza']))
print(sorted(['azzza', 'adaaaaaaaaaa', 'zzzzza'], key=len))
print(sorted(['azzza', 'adaaaaaaaaaa', 'zzzzza'], key=len, reverse=True))

print(sorted((19, 28, -35, 47)))
print(sorted((19, 28, -35, 47), key=lambda x: x % 10))
print(sorted((19, 28, -35, 47), key=abs))
print(sorted((19, 28, -35, 47), key=abs, reverse=True))

print(sorted('bcda'))  # ['a', 'b', 'c', 'd']

print(sorted({10, 20, 16}))  # [10, 16, 20]
print(sorted({19, 28, 37}, key=lambda x: x % 10))  # [37, 28, 19]

# 列表推导式
# 两个应用场景   1. 条件 筛选过程  2. 转化 映射过程

# 映射   map(函数,序列)
l = [1, 2, 3, 4]
# 将l中的每一个元素 转化为10倍
print(tuple(map(lambda x: x * 10, l)))
# 将l中的每一个元素都转化为字符串类型
print(list(map(lambda x: str(x), l)))
print(list(map(str, l)))
# 筛选 满足条件的内容 filter(函数,序列)
# range(10)  所有的偶数
# range(10) ---  0 1 2 3 4 5 5 6 7 8
# lambda x: x % 2 -- 0 1 0 1 0 1 0 1 0 1  --非零即为 True   容器 非空既为True
print(list(filter(lambda x: x % 2, range(10))))  # [1, 3, 5, 7, 9]
print(list(filter(lambda x: x % 2 == 0, range(10))))
l = ['abc', 'dec', 'bdf', 'def']
# 筛选 列表中元素的最后一个字符为c的
print(list(filter(lambda x: x[-1] == 'c', l)))
# 累计  累加和  累乘  字符串的拼接
from functools import reduce
# reduce(函数,序列)
# 累加求和   1-100的和   range(1,101)
print(reduce(lambda x, y: x + y, range(1, 101)))
# 1-10的乘积   range(1,11)   阶乘
print(reduce(lambda x, y: x * y, range(1, 11)))
# 字符串的拼接
l = ['a', 'b', 'c']
print(reduce(lambda x, y: x + '+' + y, l))
l = [1, 2, 3]
print(reduce(lambda x, y: str(x) + '+' + str(y), l))  # 1+2+3

2.8排序算法

2.8.1冒泡排序

# 冒泡排序 【升序】
# 排序规则
# 每次都从索引为0的位置开始,相邻的两个元素两两比较,如果前者大于后者,则交换位置
# l = [46,28,59,17,38]
# 第一次  [28,46,17,38,59]    产生一个最大值
# 第二次  [28,17,38,46,59]    产生第二个最大值
# 第三次  [17,28,38,46,59]    产生第三个最大值
# 第四次  [17,28,38,46,59]    最后的两个数排列好

# 如果列表中有n个数据 总共需要 排序 n-1 次
# 每一次的排序过程 都是从下标为0开始 与相邻的元素 两两比较  如果前者大于后者,则交换位置
l = [46, 28, 59, 17, 38, 50, 60, 10, 12]
# 外层循环 控制 整个的循环次数
for i in range(len(l)-1):
    for j in range(len(l)-i-1):
        if l[j]>l[j+1]:
            l[j],l[j+1] = l[j+1],l[j]
print(l)

2.8.2选择排序

# 选择排序 【升序】
# 排序规则
# 从未排序的序列中 找到最小值的位置   和索引为0 两者交换
# 从未排序的序列中 找到最小值的位置   和索引为1 两者交换
# 从未排序的序列中 找到最小值的位置   和索引为2 两者交换
# 重复。。。
# l = [46,28,59,17,38]
# 第一次  [17,28,59,46,38]
# 第二次  [17,28,59,46,38]
# 第三次  [17,28,38,46,59]
# 第四次  [17,28,38,46,59]

l = [46, 28, 59, 17, 38, 50, 60, 10, 12]
# 外层循环  控制循环的次数
for i in range(len(l)-1):
    min =i
    for j in range(i+1,len(l)):
        if l[j]<l[min]:
            min = j
    l[i],l[min]=l[min],l[i]

2.8.3插入排序

# 插入排序  【升序排序】
# 排序规则
# 第一次 从下标为1 开始  和前面的元素逐个比较,如果前面的元素大于后面的元素 ,则两个交换位置
# 第二次 从下标为2 开始  和前面的元素逐个比较,如果前面的元素大于后面的元素 ,则两个交换位置
# 第二次 从下标为3 开始  重复执行
# l = [46,28,59,17,38]
# 第一次  [28,46,59,17,38] -- 前两个数据 已经排好序的
# 第二次  [28,46,59,17,38] -- 前三个数据 已经排好序
# 第三次  [17,28,46,59,38] -- 前四个数据已经排好序
# 第四次  [17,28,38,46,59] -- 全部排好
l = [46, 28, 59, 17, 38]
# 外层函数 1. 控制循环的次数  2. 控制当前要插入的数据
for i in range(1, len(l)):  # 1 2 3 4  len-1
    # 里层循环 控制的两两比较的数据
    for j in range(i, 0, -1):
        # 比较
        if l[j] < l[j - 1]:
            l[j], l[j - 1] = l[j - 1], l[j]
        else:
            # 结束的是里层循环
            break
print(l)


2.8.4快速排序(最重要)

# 快速排序
# 递归  -- 函数中自己调用自己   递归  有规律  出口
# 排序规则
# 找到一个基准值,把数据分为两部分 一部分是比基准值大 一部分是比基准值小
# 在各部分中,继续上面的操作
# 出口 -- 空列表  列表中只有一个数  长度<=1
# l = [46,28,59,17,38]
#  [28,17,38]     基准值 46  [59]
#  [17] + [基准值28] + [38]  +  [基准值 46] + [59] ---- [17,28,38,46,59]

# 递归
def quick_sort(l):
    if len(l) <2: # len = 0 len=1
        return l
    else:
        # 找基准值
        base_num = l[0]
        # 大
        big_l = []
        # 小
        small_l = []
        for i in l[1:]:
            if i > base_num:
                big_l.append(i)
            else:
                small_l.append(i)
        # return quick_sort(small_l) + [base_num] + quick_sort(big_l)
        return quick_sort(big_l) + [base_num] + quick_sort(small_l)

print(quick_sort([46, 28, 59, 17, 38]))

深浅拷贝

列表、字典、集合 有copy()

深浅拷贝 实现使用了copy的模块

import copy

l = [[1, 2, 3], [4, 5, 6]]
# 核心区别 在于内层是否产生新的
# 深拷贝  内层产生新的
deep_l = copy.deepcopy(l)
# 两个数据 完全独立 互不影响
l.append([7,8,9])
print(l)  # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(deep_l)  # [[1, 2, 3], [4, 5, 6]]

deep_l.append(10)
print(deep_l)

print(l)

l = [[1, 2, 3], [4, 5, 6]]
# 浅拷贝  内层不产生新的
copy_l = copy.copy(l)
# 在外层增加数据
l.append([7,8,9])  # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(l)
print(copy_l)  # [[1, 2, 3], [4, 5, 6]]

#如果修改的是内层数据  浅拷贝内层数据引用原来的地址
l[0].append(100)
print(l)   # [[1, 2, 3, 100], [4, 5, 6], [7, 8, 9]]
print(copy_l)  # [[1, 2, 3, 100], [4, 5, 6]]

# 地址的引用   def my_add    f = my_add
l = [[1, 2, 3], [4, 5, 6]]
l1 = l   # 传递的地址  不管内外 都引用原来的地址
l.append([7,8,9])
print(l)
print(l1)
l[0].append(100)
print(l)
print(l1)
l1[-1].append(1000)
print(l1)
print(l)

装饰器

本质是在简化代码

作用:啊啊不修改原有代码的基础上 增加新的功能

核心: 虽然还是他, 但其实不是他

def my_add(a,b):
    return a+b
def my_sub(a+b):
    return a-b
def sleep():
    time.sleep(1)

包和模块

模块

什么是模块?一个python文件就是一个模块,模块分为三类:

  1. 系统模块【安装python环境自带的】
  2. 三方模块【别人写好,上传到网站的,如果使用,需要下载pip install xxx
  3. 自定义模块【自己写的模块】
pip 常用的指令
查看当前环境的三方模块  pip list
下载模块  pip install 模块名
卸载模块  pip uninstall 模块名
下载知道那个版本的模块 pip install 模块名==版本号

模块之间是可以相互调用的,先进行调入,导入方式

1.import 模块名
    使用方法 用的时候模块名.操作
2.from 模块名 import 操作名
    使用  直接使用操作名
3. form 模块名 import *
    *代指该模块下的所有内容
    但是 如果在模块中

比较特殊的文件夹

和普通的文件夹的区别,包中自带一个文件__init__.py文件

__init__.py的作用

  • 作为普通目录和包的区别
  • 调用包的内容的时候 首先执行文件中的内容

包的作用

  • 分类管理
  • 增大命名空间

调用包中内容,方式

包———文件夹——文件夹——文件夹


1.

常用的模块

string模块

random模块

math模块

calendar模块(日历模块)

time模块

datatime模块

os模块

os.path模块

就可迭代对象

interable

能够逐一迭代,并返回成员的对象,称为可迭代对象

可迭代对象实现了一个可迭代协议 __inter__ 可以简单理解为,能够for in遍历的都是可迭代对象

#判断数据类型是否为指定类型
isinstance([1,2,3],list)

迭代器

属于可迭代对象 对于迭代器数据来书 取数只能向后 不能向前 取完就没有了(一次性的,取完就没有了)

可迭代对象可以变成迭代器inter(可迭代对象)

取数的方式:

  1. 普通遍历 for in..
  2. next()取数

生成器

面向对象

对于面向对象来说,是一种思维方式,更符合人类的一种思维方式

类 对象

  • 类 是一个抽象的概念 同一类对下岗的特点和行为进行归纳,形成一个抽象的概念。
  • 对象 是一具体的实例,在该类的特征下,实实在在存在的实体
str  --数据类型   --类-- 使用一堆引号包含
对象'对象' 'bcd'

如何构建类

  1. 对对象的共同的特征和和共同的行为进行提取,对这些信息进行描述

    • 特征称为对象的属性

    • 行为称为对象的方法

      举例:
          小狗:
              特征: 身高  性别 体重
              行为: 汪汪叫  拆家
      
构建类的语法
class 类名():
class 类名(object)
class 类名:


class 类名:
    #定位属性 初始化方法  作用:给该类的对象进行初始化特征并赋值
    def __init__(self,参数1,参数2):
        self.特证名 = 参数1
        self.特证名 = 参数2
    #定义方法  行为
    def 函数名(self,参数1):
        pass
        
class --定义类的关键字
类名 --满足命名规范
    建议使用大驼峰命名法  每个单词的首字母大写
    小驼峰命名法  第一个单词的首字母小写 其他单词的首字母大学
__init__  初始化方法 给该类的对象进行初始化特则会那个 并进行赋值
self 指的是调用该方法的对象 默认self 可以修改为其他
定位的行为 函数名 按照之前函数的命名就可以
#定义类
class Dog:
    def __init__(self,name,age,sex):
        #self.特征 = 参数
        self.name = name #注意这两个不是一个东西, 前面的self.name 是特征,后面的name是参数
        self.age = age
        self.sex = sex
    #定义行为 其实就是定义一一个个的函数
    def chai_house(self):
        print('{}拆家呢'.format(self.name))
    def wang_wang(self):
        print('{}汪汪叫'.format(self.name))
#根据类创建对象   一个类是可以有多个对象的
#构建对象的语法 类名(特征值)
dog1=Dog(name='蛋蛋',age='3',sex='公')
dog2=Dog(name='小黄',age='4',sex='母')
print(dog1.name)  #蛋蛋
dog1.chai_house() #蛋蛋拆家呢
dog1.wang_wang()  #蛋蛋汪汪叫
dog2.chai_house() #小黄拆家呢
dog2.wang_wang()  #小黄汪汪叫

类属性和对象属性

对象属性是跟随对象一起创建,当对象被销毁吗,对应的属性一起被销毁

对象的属性之间是相互的独立 互不干扰的

类属性直接定义在类中

被所有的对象所共有 是该类队形的共同特征

类属性 可以类调用 可以对象调用 但是仅能类修改

# 对象属性  定义在__init__函数中
# 对象是跟随对象一起创建,当对象被销毁,对应的属性一起被销毁
# 对象的属性之间是相互独立,互不干扰的
# 对象属性只能对象调用

# 类属性   直接定义在类中
# 被所有的对象所共有  是该类对象的共同的特征
# 类属性  可以类调用 可以对象调用  但是仅能类修改
4444
class Dog:
    age = 5  # 类属性
    def __init__(self,name):  # name  对象属性
        self.name = name
dog1 = Dog('小黑')
dog2 = Dog('小花')
dog3 = Dog('大白')
# 对象属性 对象进行调用
print(dog1.name)
print(dog2.name)
print(dog3.name)
# age 类属性  可以类调 可以对象调
print(dog1.age)
print(dog2.age)
print(dog3.age)
# 类来调用  类名
print(Dog.age)
# 如果想修改 只能类名进行修改
# 错误示范  对象修改  获取再赋值
# dog1.age = 18
# print(dog1.age)   # 实际上是给dog1增加了一个对象属性
#
# print(dog2.age)
# print(dog3.age)
# print(Dog.age)


# 修改类属性的操作 类名修改
Dog.age = 18
print(dog1.age)
print(dog2.age)
print(dog3.age)44

常见的魔术方法

不需要手动调用,在适当的时机进行自动调用 魔术方法使用__内容__ 系统提供好的

垃圾回收机制

python中使用引用计数原则实现垃圾回收的

每一个python对象都会有一个计数器,这个计数器从0开始,每增加一个引用,计数器+1

如果有变量取消了引用,了计数器就会 -1 当计数器为0 便是这块地址美哟偈引用,表示程序不再需要

会自动调用 __del__进行垃圾回收

# 魔术方法   不需要手动调用,在适当的时机进行自动调用  魔术方法使用__内容__   系统提供好的
# __new__    构造方法    实例化对象的
# __init__   初始化方法   对对象进行初始化特征并赋值  执行时机在 __new__ 之后
# __del__    析构方法    没有任何引用的时候,内存的释放和回收
# 默认继承自object  --  所有类的总类型

# __str__
# __repr__

# 和运算符相关  __add__   __sub__

class Dog:
    # def __new__(cls, *args, **kwargs):
    #     return object.__new__(cls)

    def __init__(self, name):  # name  对象属性
        self.name = name

    def chai_house(self):
        print(f'{self.name}正在拆家')

    # def __del__(self):
    #     print(f'{self.name}正在调用__del__')

    def __str__(self):
        # 注意 要有返回值 要求 返回的是字符串
        return f'Dog(name={self.name})'

    __repr__ = __str__
    # def __repr__(self):
    #     return f'Dog(name={self.name})'


dog1 = Dog('小黑')
dog2 = Dog('小花')
# del dog1
# print('------------文件执行完---------------')
# 文件中的所有内容已经被执行完了  内存被释放
# dog2.chai_house()

# 垃圾回收机制
# python中使用引用计数原则实现垃圾回收的
# 核心思想:每一个python对象都会有一个计数器,这个计数器从0开始,每增加一个引用,计数器+1,
# 如果有变量取消了引用,计数器就会-1,当计数器为0,表示这块内存地址没有任何引用,表示程序不再需要,
# 自动调用__del__进行垃圾回收
# 文件所有的代码都被执行完,就会进行垃圾回收,内存释放,自行调用__del__
# 获取对象的引用个数
import sys
# 文档中解读  得到的个数比预期 + 1
# print(sys.getrefcount(dog1))  # 2
# a = dog1
# print(sys.getrefcount(dog1))  # 3
# b = dog1
# print(sys.getrefcount(dog1))  # 4
# a = 10
# print(sys.getrefcount(dog1))  # 3
# b = 20
# print(sys.getrefcount(dog1)) # 2
# del dog1
# # print(sys.getrefcount(dog1))
# print('--------------执行完成--------------------')

# __str__  __repr__
# 默认打印对象 打印的是地址  如果打印其他内容 需要重写 __str__   1. 返回值    2. 返回值 字符串
print(dog1)
print(dog2)
# 如果想在容器中  打印 对象的自定义内容  __repr__
l = [dog1, dog2]
print(l)


运算符的魔术方法

# 运算符的魔术方法
# 加  __add__    减法  __sub__  乘 __mul__  除  __truediv__
# >   __gt__  greater than
# >=  __ge__  greater equal
# <   __lt__  less than
# <=  __le__  less  equal
# ==  __eq__

# 列表 *  -- 将数据重复  [1,2,3] * 3
# 定义一个类  * -- 将每一个数据乘n  [1,2,3}*3 -- [3,6,9]

class A:
    def __init__(self,l):
        self.l = l

    def __mul__(self, other):
        res = []
        for i in self.l:
            res.append(i*other)
        return res
a = A([1,2,3,4,5])
print(a*3)

# 重点内容   __eq__  实现的是 ==
# is   身份运算符 (判断两个数据的内存地址是否一样)

# == 和 is 的区别
# 如果在类中 没有重写 __eq__ 默认 == 和 is是一样的 也是用来判断两个数据的内存地址是否一样
# 但是 通常情况下,==被用来判断伪相等

l =  [1,2,3]
l2 = [1,2,3]
print(l == l2) # 重写的规则

# 身份证    名字 小红 小明  身份证号   被用来作为人的唯一判断标识
class Card:
    def __init__(self,name,cid):
        self.name = name
        self.cid = cid
    # 为了迎合生活场景  == 用作判断伪相等  需要重写__eq__
    def __eq__(self, other):
        return self.cid == other.cid   # == 的规则是 数据的cid 和另一个数据的cid一样

c1 = Card('小红1','110110')
c2 = Card('小红2','110110')
print(id(c1))
print(id(c2))
print(c1 == c2)

类和类之间的关系

一个类中 包含了 另一个类的实例对象 体现的是一个整体和部分的关系

教师类 属性 教室的名字 学生们

学生类 属性 姓名 年龄 性别 分数

# 聚合关系  一个类中包含了另一个类的实例对象  体现的是整体和部分 关系
# 教室类   属性  教室的名字  学生们
        # 行为  添加学生
            # 删除学生
            # 根据学生成绩排序
            # 获取每个性别的人数
# 学生类   属性  姓名 年龄 性别 分数
class Student:
    def __init__(self, name, age, gender, score):
        self.name = name
        self.age = age
        self.gender = gender
        self.score = score

    def __str__(self):
        return f'Stu(name={self.name},age={self.age},gender={self.gender},score={self.score})'

    __repr__ = __str__

class ClassRoom:
    def __init__(self, class_name, students=None):
        if students == None:
            students = []
        self.class_name = class_name
        self.students = students
    # 增加学生  增加一个学生  如果一次增加多个????
    def add_stu(self,student):
        self.students.append(student)
    # 删除学生  给定删除的特点  名字
    def remove_stu(self,name):
        # 遍历每一个学生 看一下 名字是不是指定的名字 如果是  列表移除某个学生
        for stu in self.students:
            # stu 指的是???  表示的就是每一个学生类对应的对象  获取对象的属性
            if stu.name == name:
                self.students.remove(stu)
    # 排序
    def sort_by_score(self):
        # 列表的排序  列表.sort    sorted
        return sorted(self.students,key=lambda stu:stu.age)

s1 = Student('小红', 18, '女', 90)
s2 = Student('小明', 16, '男', 80)
s3 = Student('乐乐', 19, '男', 60)
s4 = Student('小倩', 17, '女', 40)

c1 = ClassRoom('python', [s1, s2])
print(c1.students)
c1.add_stu(s3)
print(c1.students)
c1.remove_stu('小红')
print(c1.students)
c1.add_stu(s1)
c1.add_stu(s4)
print(c1.students)
print(c1.sort_by_score())
继承关系

​ 将两个或者多个普通类共同的属性和行为,提取到一个共通类中,使用继承的语法,使用共通类中的信息,这个过程就是继承

class 类名(父类类名):---继承的语法,代表当前类继承自父类
    pass

父类和子类的关系子类继承自父类,父类派生出子类

对于方法的重写

一般情况下,父类的内容,子类可以直接使用,但是有特殊情况

  1. 子类的实现和父类部分一样
  2. 子类的实现和父类的完全不一样

当子类对方法及你想重写之后,

'''
学生类
    属性 姓名 年龄 性别
    行为 干饭 睡觉

工人类
    属性 姓名 年龄 性别  工龄
    行为 干饭 睡觉 打工

共同的属性和行为 提升 共通类  使用继承的语法 继承这些内容
人类
    属性  姓名 年龄 性别
    行为  干饭 睡觉
'''
class Person:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def eat_fan(self):
        print(f'{self.name}在干饭')

    def sleep(self):
        print(f'{self.name}在睡觉')

class Student(Person):
    pass

class Worker(Person):
    def __init__(self,name,age,gender,work_age):
        # name,age,gender 父类都有  使用父类  需要将父类 继承
        # 1. 父类类名.__init__(self,name,age,gender)
        # Person.__init__(self,name,age,gender)
        # 2. super -- 表示父类  super(子类类名,self).__init__(name,age,gender)
        super(Worker,self).__init__(name,age,gender)
        # 3. 建议使用  第二种的简化步骤  super().__init(name,age,gender)
        # super().__init__(name,age,gender)
        self.work_age = work_age
    def dang_dog(self):
        print(f'{self.name}在打工')

    def sleep(self,where):
        print(f'{self.name}在{where}睡觉')
`
# 创建学生对象
s1 = Student('小明',8,'男')
s1.eat_fan()
s1.sleep()
# 创建工人对象
w1 = Worker('小红',30,'女',10)
w1.eat_fan()
w1.sleep('桥底下')
w1.dang_dog()

python支持多继承,多继承,属性默认继承自第一个父类

class Father1:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def run(self):
        print('跑跑跑')

class Father2:
    def __init__(self, height):
        self.height = height

    def fly(self):
        print('飞飞飞')


class Son(Father1, Father2):
    # 多继承  属性默认继承自第一个父类
    # 如果想把父类的属性都继承 需要重写__init__
    def __init__(self,name,age,height):
        # super().__init__(name,age)
        # super().__init__(height)不能使用这种方法
        Father1.__init__(self,name,age)
        Father2.__init__(self,height)

s1 = Son('小明',10,180)
s1.run()
s1.fly()

面向对象的三大特征

  1. 封装

    在类中,对属性或者方法进行隐藏,在外部进行实例化对象之后,不能通过对象.属性或者对象.方法的操作进行获取或者调用但是流出对应的访问接口调用封装好的属性和方法,封装的思想(隐藏一切可隐藏的内容,只暴露接口)

    '''
    实例方法--也被称为对象方法 定义在类中
        特点:第一个参数是self  self表示的是调用该方法的对象
        调用:对象调用(建议使用的方式)  类名也可以调,但是要手动给self传实例对象
    类方法(主要用来修改类属性)
        特点:
        1.第一个参数是cls
        2.需要一个装饰器进行装饰
        可以类调用,也可以对象调用,但是推荐使用类调用
    静态方法:
        特点:
            1.没有self 和 cls
            2.需要一个装饰器进行装饰 装饰器名字:staicmethod
            3.本质和类没有关系 只是放在类中 方便维护
    '''
    import time
    
    class Dog:
        # 类属性
        # 私有化 私有化后的属性只能在类中使用
        __age = 18
        def __init__(self,name):  # name 对象属性
            self.name = name
    
        def kan_house(self):
            print(f'{self.name}在看家')
    
        # 提供对外的访问接口
        def get_age(self):
            return self.__age
    
        # 修改类属性  类方法
        # 类方法的特点 1. 第一个参数 cls   2. 需要一个装饰器进行装饰 classmethod
        # 调用  类名来调用(建议)  可以对象调用
        @classmethod
        def change_age(cls,new_age):
            cls.__age = new_age
            return cls.__age
    
        # 静态方法
        # 特点 1. 没有self 和 cls    2. 需要一个装饰器进行装饰器  staticmethod
        # 其实和类没有关系  只是放在类中 方便维护
        # 方法 实现 放在类外也是可以
        @staticmethod
        def show_time():
            return time.time()
    
    dog1 = Dog('小黑')
    dog2 = Dog('小花')
    dog1.kan_house()
    Dog.kan_house(dog1)
    
    print(dog1.get_age())
    
    print(Dog.change_age(100))
    
    # print(dog1.__age)
    
    print(dog1.change_age(80)) #
    print(dog2.get_age())
    
    #  _类名__特征名
    # print(dog1._Dog__age)
    
    print(Dog.show_time())
    
  2. 继承

    简化代码的一种方法

  3. 多态

​ 在继承的基础上,不同的数据呈现出来的不同形态

​ 但是python是动态数据类型的,多态没有太多展示,没有太多意思

​ 实现多态的条件

​ 1. 有继承关系

####异常捕获

正则表达式

是一种特殊的字符串。但是有自己独立的语法,可以进行判断、验证、提取

有自己独立的处理引擎,语法适用于所有的编程语言,正则表达式的处理效率比内置的字符串方法低,能用字符串方法进行处理,先用字符串方法,如果字符串方法处理不了或者处理特别麻烦,使用正则

python中提供的提供正则的模块叫做re模块

1.re.complie(正则表达式,匹配对象) -- 将正则表达式编译成正则对象
2.正则对象.match(字符串)          --在字符串中产找内容 查找的特点:从字符串的最左边开始,如果最左边能匹配,就能找到,如果最左边匹配不了,返回None
3.正则对象.search(字符串)         --在字符串中查找,查找特点 在整个字符串中查找,找到的是满足田间的第一个,如果米欸有满足条件的,返回None
4.正则对象.fullmatch(字符串)      --在字符中查找 查找特点 要求字符串从头到尾满足正则表达式
5.正则对象.findall(字符串)		   --在字符串中找所有满足正则表达式的  返回结果是列表 如果在字符串中没有满足条件的,返回的是空列表
6.正则对象.split(字符串)          --将字符串按照指定的切割符号进行切割
    'abc-def-ghj*nmk^gueh#gkgd'  #会把特殊符号都切割
7.正则对象.sub(新,旧,字符串)     --在字符串中 将正则表达式匹配到的内容日换成新内容

正则语法

匹配单个字符
匹配符号 含义
. 匹配任意符号 除\n之外
[字符们] [abc] – 标识这个位置上的符号可以是a 可以是b 可以是c
[A-Z]若果对相应的符号ascii连续 可以使用-连接[a-z][0-9]
[a-zA-Z0-9]–标识这个位置的符号,可以是英文或数字
[^0-9] ^表示 非 表示非0-9的符号
\d 表示数字 等同于 [0-9]
\D 表示 非 数字 等同于[^0-9]
\w 表示 数字 字母 下划线中的任意一个(这里的字符不单指英文)
\W 表示 非 数字字母下划线中的任意一个
\s 表示的是空白符号
\S 表示的非空白字符
符号 含义
^X 字符串以指定内容开头
X$ 字符串以指定内容结尾
数量词
符号 含义
* 表示前面的内容出现任意次(0,1,好多次)
+ 表示前面的内容出现至少一次 1 次 好多次 >=1
表示前面的内容出现至多一次 1次 0次
{m} 表示前面的内容固定出现m次
{m,n} 表示前面的内容出现至少m次,至多n次
分组匹配

某个位置的内容可能有多种情况,把多种写出,用|,并用小括号括起来

匹配标记

re.S  让.匹配所有
re.I  忽略大小写
s = '''a1

网络数据采集

爬虫

通过编写程序,模拟浏览器上网,批量采集数据,数据是既有数据,网站提供的数据

合法性

爬虫本身是不被法律禁止,但是具有违法风险,爬虫不要干扰网站的正常内容,不要采集关于个人信息相关的内容

robots协议–君子协议

每一个网站在robots协议中写好了哪些内容可爬取,但是君子协议不会对爬虫程序作出阻止效果

反爬机制

网站设定了相关的机制 防止爬虫程序对数据的获取

#####反反爬策略

爬虫程序中可以指定相关的策略和解决方案,破解网站的反爬机制,进而获取数据

客户端和服务器端

客户端:供用具使用的一端

服务端:给用户提供服务的,客户端显示的内容是来源于服务器的,数据信息存储在服务器端的,客户端需要什么数据,想服务传递信息,服务器接收到信息之后,进行数据查找,把找到的数据返回给客户端

请求和相应

  • 请求:客户端把数据信息发送给服务器,这个过程称为请求
  • 响应:服务器接收到请求,查找数据,把相应的数据返回给客户端,这个过程称为响应
请求方式
  1. get请求 明显特点:请求的参数直接拼接在网址上,拼接方式?key=value&key=value

    参数直接暴露在了网址上,所以不安全

  2. post请求 请求参数不会直接暴露在网址上,安全性比较高

    客户端向服务器提交信息,需要服务器进行验证,这种请求一般用post

url –网址

统一资源定位符,通过url定位获取相应的资源

格式 协议://域名或者ip:端口/资源路径?key=value&key=value

http协议

超文本传输协议,是网络数据通信的基础

https 在http的基础上做了ssl加密,数据传输更安全

又被称为request响应[response]协议,客户端和服务器端请求和响应的按标准

请求:向服务器传递信息,称为请求

客户端向服务器传递信息,携带一个请求报文

包含的部分:请求行 请求头 空行 请求体、

请求行(请求方式  资源路径 协议版本号)

常见的状态码

200 - 表示相应成功

爬虫流程

  1. 指定url
  2. 发送请求,接受响应,获取相应数据 两种发送请求的方式 request selenium
  3. 解析数据,把想获取的内容解析出来 正则解析、css选择器解析、xpath解析
  4. 存储数据txt文件 excel文件 csv文件[逗号分隔值文件] 图片 视频 音频 数据库

CSS选择器查找

1.id 选择器  指标签有一个属性名为id 唯一选择器 在html文档中 id = '值' 是唯一的
    <div id = 'haha'>
    使用方法:
        #haha  --表示定位的 具有id=haha的标签
2.class 选择器 类选择器 --变迁有一个属性名为class
    <div class ='haha'>
    结合ctrl+f查找 根据查找 确定数量
3.标签选择器 元素选择器 指标签名称为指定内容
4.包含 选择器
    父子关系
        父选择器 > 子选择器
    
    先辈与后辈关系
        先辈选择器 后被选择器
5.兄弟选择器
    A~B 指A标签后的所有B
    
    A+B指A标签后紧邻的那一个B
6.属性选择器
    id class 也是属性 知识比较特殊被单独赋予了两个符号
    选择器[属性] --表示的是具有某个属性的
    选择器[属性名=值] 表示的是具有某个属性名且对应的值为指定内容的
    选择器[属性名^=指定内容]--表示的是具有某个属性名且对应的值以指定内容结尾的
    选择器[属性名*=指定内容]  表示的是具有某个属性名 且对应的值包好指定内容的
7.结构选择器
    父选择器>子选择器:first-child
    父选择器>子选择器:last-child

xpath解析

html超文本标记语言,组成是标签

xml可扩展标记语言,组成是双标签,标签名字支持自定义

xpath解析原理

  1. 实例化etree对象 导入方式 from lxml import etree把获取的源码数据加载到该对象中

    from lxml import etree
    #数据的来源
    #如果数来源于本地文件
    etree.parse(文件的路径)
    
    2.如果数据来源于互联网 
    etree.HTML(获取的文本数据)
    
  2. 利用xpath语法,实现标签的定位与内容的获取

    tree.expath(xpath语法)
    
    xpath语法  路径解析法
    1.路径查询
        /   从根节点开始查找 html文档
        //  全局查找
    2.谓语查找
        具有某个属性 属性 --@
        具有某个属性的标签 路径[@属性]