Python入门笔记(Duruofu)

第一部分 计算机基础知识(了解即可)

计算机的组成

计算机由两部分组成:硬件 和 软件
硬件包含:键盘、鼠标、显示器、CPU、主板、内存、硬盘 。。。硬件是看的见摸得着的
软件包含:系统软件(windows、macOS、Linux)和应用软件(office 、QQ、绝地求生)软件是看的见摸不着的,软件负责控制计算机中的硬件

计算机的使用方式

我们必须要通过软件来对计算机完成各种操作,但是注意,软件中并不是所有的功能都会对用户开放,用户需要调用软件提供的接口(Interface 交互界面)来操作计算机
用户界面分成两种:TUI(文本交互界面)和 GUI(图形化交互界面)

windows的命令行

命令行就是文本交互界面,通过命令行可以使用一个一个的指令来操作计算机,任何的计算机的操作系统中都包含有命令行(windows、linux、macOS)
命令行有多个不同的名字:命令行、命令行窗口、DOS窗口、命令提示符、CMD窗口、Shell、终端、Terminal

1.如何进入到命令行

  1. win + R 出现运行窗口,输入cmd,然后回车

Python笔记 - 图1

2.命令行的结构

  1. - 版本及版权声明(一般没有什么用)
  2. Microsoft Windows [版本 10.0.16299.431]
  3. (c) 2017 Microsoft Corporation。保留所有权利。
  4. 命令提示符
  5. C:\Users\lilichao>
  6. C:
  7. - 当前所在的磁盘根目录
  8. - 可以通过 x: 来切换盘符(x表示你的盘符)
  9. \Users\lilichao
  10. - 所在磁盘的路径,当前所在的文件夹
  11. - cd 来切换目录
  12. >
  13. - 命令提示符,在大于号后边可以直接输入指令

3.常用的dos命令

  1. dir 查看当前目录下的所有文件(夹)<br /> cd 进入到指定的目录<br /> . 表示当前目录<br /> .. 表示上一级目录<br /> md 创建一个目录<br /> rd 删除一个目录<br /> del 删除一个文件<br /> cls 清除屏幕<br />命令的语法<br /> 命令 [参数] [选项]

4.小技巧

  • 方向键上下,查看命令的历史记录
    • tab键自动补全命令

环境变量

环境变量指的就是操作系统当中的一些变量。可以通过修改环境变量,来对计算机进行配置(主要是来配置一些路径的)

1.查看环境变量

  1. > 右键 计算机(此电脑),选择属性<br /> > 系统界面左侧选择 高级系统设置<br /> > 选择环境变量<br /> 环境变量界面分成了两个部分,上边是用户环境变量,下边是系统环境变量 建议只修改用户的环境变量,不要修改系统的环境变量

2.添加环境变量

  1. > 通过新建按钮添加环境变量<br /> > 一个环境变量可以由多个值,值与值之间使用;(英文)隔开

3.修改环境变量

  1. > 通过编辑按钮来修改环境变量

4.删除环境变量

  1. > 通过删除按钮来删除环境变量

path环境变量

path环境变量中保存的是一个一个的路径。
当我们在命令行中输入一个命令(或访问一个文件时),系统会首先在当前目录下寻找,如果找到了则直接执行或打开。 如果没有找到,则会依次去path环境变量的路径中去寻找,直到找到为止。如果path环境变量中的路径都没有找到,则报错 ‘xxx’ 不是内部或外部命令,也不是可运行的程序或批处理文件。
我们可以将一些经常需要访问到的文件会程序的路径,添加到path环境变量中,这样我们就可以在任意的位置访问到这些文件了

注意事项:
1.如果环境变量中没有path,可以手动添加
2.path环境变量不区分大小写 PATH Path path
3.修改完环境变量必须重新启动命令行窗口
4.多个路径之间使用;隔开

进制

十进制(最常用的进制)

  • 十进制就是满十进一的进制
  • 十进制当中一共有10个数字
    0 1 2 3 4 5 6 7 8 9
  • 十进制如何计数
    0 1 2 3 4 5 6 7 8 9 10 11 12 。。。 19 20 。。。29 30

二进制(计算机底层使用的进制)

  • 满二进一
  • 二进制中一共有2个数字
    0 1
  • 二进制如何计数
    0 1 10 11 100 101 110 111 1000
  • 所有的数据在计算机底层都是以二进制的形式保存的,计算机只认二进制
  • 可以将内存想象为一个一个的小格子,小格子中可以存储一个0或一个1
  • 内存中的每一个小格子,我们称为1bit(位)
    bit是计算机中的最小的单位
    byte是我们最小的可操作的单位
    8bit = 1byte(字节)
    1024byte = 1kb(千字节)
    1024kb = 1mb(兆字节)
    1024mb = 1gb(吉字节)
    1024gb = 1tb(太字节)

八进制(一般不用)

  • 满八进一
  • 八进制中一共有8个数字
    0 1 2 3 4 5 6 7
  • 八进制如何计数
    0 1 2 3 4 5 6 7 10 11 。。。 17 20 。。。27 30

十六进制

  • 满十六进一
  • 十六进制中一共有16个数字,由于十六进制是满16才进位,所以十六进制中引入了a b c d e f来表示 10 11 12 13 14 15
    0 1 2 3 4 5 6 7 8 9 a b c d e f
  • 十六进制如何计数
    0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 。。。 1a 1b 1c 1d 1e 1f20 21 22 。。。 2a 2b 2c 2d 2e 2f 30
  • 我们在查看二进制数据时,一般会以十六进制的形式显示

文本文件和字符集

文本分成两种,一种叫做纯文本,还有一种叫做富文本

  • 纯文本中只能保存单一的文本内容,无法保存内容无关的东西(字体、颜色、图片。。。)
  • 富文本中可以保存文本以外的内容(word文档)
  • 在开发时,编写程序使用的全都是纯文本!
  • 纯文本在计算机底层也会转换为二进制保存,将字符转换为二进制码的过程,我们称为编码
    将二进制码转换为字符的过程,我们称为解码编码和解码时所采用的规则,我们称为字符集
  • 常见的字符集:
    ASCII
    • 美国人编码,使用7位来对美国常用的字符进行编码
    • 包含128个字符
      ISO-8859-1
    • 欧洲的编码,使用8位
    • 包含256个字符
      GB2312
      GBK
      国标码,中国的编码
      Unicode
      万国码,包含世界上所有的语言和符号,编写程序时一般都会使用Unicode编码Unicode编码有多种实现,UTF-8 UTF-16 UTF-32最常用的就是UTF-8
  • 乱码
    编写程序时,如果发现程序代码出现乱码的情况,就要马上去检查字符集是否正确

第二部分 Python入门

什么是计算机语言

计算机就是一台用来计算机的机器,人让计算机干什么计算机就得干什么!
需要通过计算机的语言来控制计算机(编程语言)!
计算机语言其实和人类的语言没有本质的区别,不同点就是交流的主体不同!
计算机语言发展经历了三个阶段:

机器语言

  • 机器语言通过二进制编码来编写程序效率好,编写起来太麻烦

符号语言(汇编)

  • 使用符号来代替机器码
  • 编写程序时,不需要使用二进制,而是直接编写符号
  • 编写完成后,需要将符号转换为机器码,然后再由计算机执行
    符号转换为机器码的过程称为汇编
  • 将机器码转换为符号的过程,称为反汇编
  • 汇编语言一般只适用于某些硬件,兼容性比较差

高级语言

  • 高级语言的语法基本和现在英语语法类似,并且和硬件的关系没有那么紧密了
  • 也就是说我们通过高级语言开发程序可以在不同的硬件系统中执行
  • 并且高级语言学习起来也更加的容易,现在我们知道的语言基本都是高级语言
  • C、C++、C#、Java、JavaScript、Python 。。。

编译型语言和解释型语言

计算机只能识别二进制编码(机器码),所以任何的语言在交由计算机执行时必须要先转换为机器码,也就是像 print(‘hello’) 必需要转换为类似 1010101 这样的机器码 根据转换时机的不同,语言分成了两大类:

编译型语言

  • C语言
  • 编译型语言,会在代码执行前将代码编译为机器码,然后将机器码交由计算机执行
  • a(源码) —编译—> b(编译后的机器码)
  • 特点:
    执行速度特别快
    跨平台性比较差

解释型语言

  • Python JS Java
  • 解释型语言,不会在执行前对代码进行编译,而是在执行的同时一边执行一边编译
  • a(源码)—解释器—> 解释执行
  • 特点:
    执行速度比较慢
    跨平台性比较好

Python的介绍

Python是解释型语言

Python(英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/),是一种广泛使用的高级编程语言,属于通用型编程语言,由吉多·范罗苏姆创造,第一版发布于1991年。可以视之为一种改良(加入一些其他编程语言的优点,如面向对象)的LISP。作为一种解释型语言,Python的设计哲学强调代码的可读性和简洁的语法(尤其是使用空格缩进划分代码块,而非使用大括号或者关键词)。相比于C++或Java,Python让开发者能够用更少的代码表达想法。不管是小型还是大型程序,该语言都试图让程序的结构清晰明了。

Life is short you need Python (人生苦短,我用Python)

Python的用途:
WEB应用
Facebook 豆瓣 。。。
爬虫程序
科学计算
自动化运维
大数据(数据清洗)
云计算
桌面软件/游戏
人工智能
。。。

Python开发环境搭建

开发环境搭建就是安装Python的解释器
Python的解释器分类:
CPython(官方)
用c语言编写的Python解释器
PyPy
用Python语言编写的Python解释器
IronPython
用.net编写的Python解释器
Jython
用Java编写的Python解释器

Python的交互界面

当我们通过命令行来输入Python,所进入到的界面就是Python的交互界面

Python笔记 - 图2

结构:

  1. 版本和版权声明:
  2. Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)] on win32
  3. Type "help", "copyright", "credits" or "license" for more information.
  4. 命令提示符:
  5. >>>
  6. 在命令提示符后可以直接输入Python的指令!输入完的指令将会被Python的解释器立即执行!
  7. 安装Python的同时,会自动安装一个Python的开发工具IDLE,通过IDLE也可以进入到交互模式
  8. 但是不同的是,在IDLE中可以通过TAB键来查看语句的提示。
  9. IDLE实际上就是一个交互界面,但是他可以有一些简单的提示,并且可以将代码保存

交互模式只能你输入一行代码,它就是执行一行,所以他并不适用于我们日常的开发!
仅可以用来做一些日常的简单的测试!

我们一般会将Python代码编写到一个py文件中,然后通过python指令来执行文件中的代码

相关概念

1.表达式

  1. 表达式就是一个类似于数学公式的东西<br /> 比如:10 + 5 8 - 4<br /> 表达式一般仅仅用了计算一些结果,不会对程序产生实质性的影响<br /> 如果在交互模式中输入一个表达式,解释器会自动将表达式的结果输出

2.语句

  1. 在程序中语句一般需要完成某种功能,比如打印信息、获取信息、为变量赋值。。。<br /> 比如:<br /> print()<br /> input()<br /> a = 10<br /> 语句的执行一般会对程序产生一定的影响<br /> 在交互模式中不一定会输出语句的执行结果

3.程序(program)

  1. 程序就是由一条一条的语句和一条一条的表达式构成的。

4.函数(function)

  1. 函数就是一种语句,函数专门用来完成特定的功能<br /> 函数长的形如:xxx()

函数的分类:

内置函数:
  1. Python解释器提供的函数,可以在Python中直接使用

自定义函数
  1. 由程序员自主的创建的函数<br /> 当我们需要完成某个功能时,就可以去调用内置函数,或者自定义函数

函数的两个要素:

  1. **参数**<br /> ()中的内容就是函数的参数。有参数,也可以有多个参数,多个参数之间使用,隔开<br /> **返回值**<br /> 返回值是函数的返回结果,不是所有的函数都有返回值

基本语法

1.在Python中严格区分大小写
2.Python中的每一行就是一条语句,每条语句以换行结束
3.Python中每一行语句不要过长(规范中建议每行不要超过80个字符)
“rulers”:[80],
4.一条语句可以分多行编写,多行编写时语句后边以\结尾
5.Python是缩进严格的语言,所以在Python中不要随便写缩进
6.在Python中使用#来表示注释,#后的内容都属于注释,注释的内容将会被解释器所忽略
我们可以通过注释来对程序进行解释说明,一定要养成良好的编写注释的习惯
注释要求简单明了,一般习惯上#后边会跟着一个空格

字面量和变量

字面量就是一个一个的值,比如:1,2,3,4,5,6,‘HELLO’。字面量所表示的意思就是它的字面的值,在程序中可以直接使用字面量

变量(variable)变量可以用来保存字面量,并且变量中保存的字面量是不定的。变量本身没有任何意思,它会根据不同的字面量表示不同的意思

一般我们在开发时,很少直接使用字面量,都是将字面量保存到变量中,通过变量来引用字面量

变量和标识符

  1. # Python中使用变量,不需要声明,直接为变量赋值即可
  2. a = 10
  3. # 不能使用没有进行过赋值的变量
  4. # 如果使用没有赋值过的变量,会报错 NameError: name 'b' is not defined
  5. # print(b)
  6. # Python是一个动态类型的语言,可以为变量赋任意类型的值,也可以任意修改变量的值
  7. a = 'hello'
  8. # print(a)
  9. # 标识符
  10. # 在Python中所有可以自主命名的内容都属于标识符
  11. # 比如:变量名、函数名、类名
  12. # 标识符必须遵循标识符的规范
  13. # 1.标识符中可以含有字母、数字、_,但是不能使用数字开头
  14. # 例子:a_1 _a1 _1a
  15. # 2.标识符不能是Python中的关键字和保留字
  16. # 也不建议使用Python中的函数名作为标识符,因为这样会导致函数被覆盖
  17. # 3.命名规范:
  18. # 在Python中注意遵循两种命名规范:
  19. # 下划线命名法
  20. # 所有字母小写,单词之间使用_分割
  21. # max_length min_length hello_world xxx_yyy_zzz
  22. # 帕斯卡命名法(大驼峰命名法)
  23. # 首字母大写,每个单词开头字母大写,其余字母小写
  24. # MaxLength MinLength HelloWorld XxxYyyZzz
  25. #
  26. # 如果使用不符合标准的标识符,将会报错 SyntaxError: invalid syntax
  27. _b123 = 20
  28. # print(_b123)
  29. # print = 123
  30. # print(print)

数据类型

数据类型指的就是变量的值得类型,也就是可以为变量赋哪些值

1.数值:整型, 浮点型,复数

  1. # 在Python数值分成了三种:整数、浮点数(小数)、复数
  2. # 在Python中所有的整数都是int类型
  3. a = 10
  4. b = 20
  5. # Python中的整数的大小没有限制,可以是一个无限大的整数
  6. # c = 999999999999999999999999999999999999999999999 ** 100
  7. # 如果数字的长度过大,可以使用下划线作为分隔符
  8. c = 123_456_789
  9. # d = 0123 10进制的数字不能以0开头
  10. # 其他进制的整数,只要是数字打印时一定是以十进制的形式显示的
  11. # 二进制 0b开头
  12. c = 0b10 # 二进制的10
  13. # 八进制 0o开头
  14. c = 0o10
  15. # 十六进制 0x开头
  16. c = 0x10
  17. # 也可以通过运算符来对数字进行运算,并且可以保证整数运算的精确
  18. c = -100
  19. c = c + 3
  20. # 浮点数(小数),在Python中所有的小数都是float类型
  21. c = 1.23
  22. c = 4.56
  23. # 对浮点数进行运算时,可能会得到一个不精确的结果
  24. c = 0.1 + 0.2 # 0.30000000000000004
  25. print(c)

2.字符串

字符串介绍:
  1. # 字符串(str)
  2. # 字符串用来表示一段文本信息,字符串是程序中使用的最多的数据类型
  3. # 在Python中字符串需要使用引号引起来
  4. s = 'hello'
  5. # s = abc # 字符串必须使用引号引起来,不使用不是字符串
  6. # 引号可以是双引号,也可以是单引号,但是注意不要混着用
  7. s = 'hello'
  8. s = "hello"
  9. # s = 'hello" 引号不能混合使用 SyntaxError: EOL while scanning string literal
  10. # 相同的引号之间不能嵌套
  11. # s = "子曰:"学而时习之,乐呵乐呵!""
  12. s = '子曰:"学而时习之,乐呵乐呵!"'
  13. # 长字符串
  14. # 单引号和双引号不能跨行使用
  15. s = '锄禾日当午,\
  16. 汗滴禾下土,\
  17. 谁知盘中餐,\
  18. 粒粒皆辛苦'
  19. # 使用三重引号来表示一个长字符串 ''' """
  20. # 三重引号可以换行,并且会保留字符串中的格式
  21. s = '''锄禾日当午,
  22. 汗滴禾下土,
  23. 谁知盘中餐,
  24. 粒粒皆辛苦'''
  25. # 转义字符
  26. # 可以使用 \ 作为转义字符,通过转义字符,可以在字符串中使用一些特殊的内容
  27. # 例子:
  28. # \' 表示'
  29. # \" 表示"
  30. # \t 表示制表符
  31. # \n 表示换行符
  32. # \\ 表示反斜杠
  33. # \uxxxx 表示Unicode编码
  34. s = "子曰:\"学而时习之,\\\\n乐呵乐呵!\""
  35. s = '\u2250'
  36. print(s)

格式化字符串
  1. # 格式化字符串
  2. a = 'hello'
  3. # 字符串之间也可以进行加法运算
  4. # 如果将两个字符串进行相加,则会自动将两个字符串拼接为一个
  5. a = 'abc' + 'haha' + '哈哈'
  6. # a = 123
  7. # 字符串只能不能和其他的类型进行加法运算,如果做了会出现异常 TypeError: must be str, not int
  8. # print("a = "+a) # 这种写法在Python中不常见
  9. a = 123
  10. # print('a =',a)
  11. # 在创建字符串时,可以在字符串中指定占位符
  12. # %s 在字符串中表示任意字符
  13. # %f 浮点数占位符
  14. # %d 整数占位符
  15. b = 'Hello %s'%'孙悟空'
  16. b = 'hello %s 你好 %s'%('tom','孙悟空')
  17. b = 'hello %3.5s'%'abcdefg' # %3.5s字符串的长度限制在3-5之间
  18. b = 'hello %s'%123.456
  19. b = 'hello %.2f'%123.456
  20. b = 'hello %d'%123.95
  21. b = '呵呵'
  22. # print('a = %s'%a)
  23. # 格式化字符串,可以通过在字符串前添加一个f来创建一个格式化字符串
  24. # 在格式化字符串中可以直接嵌入变量
  25. c = f'hello {a} {b}'
  26. print(f'a = {a}')

复制字符串
  1. # 创建一个变量来保存你的名字
  2. name = '孙悟空'
  3. # 使用四种方式来输出,欢迎 xxx 光临
  4. # 拼串
  5. print('欢迎 '+name+' 光临!')
  6. # 多个参数
  7. print('欢迎',name,'光临!')
  8. # 占位符
  9. print('欢迎 %s 光临!'%name)
  10. # 格式化字符串
  11. print(f'欢迎 {name} 光临!')
  12. # 字符串的复制(将字符串和数字相乘)
  13. a = 'abc'
  14. # * 在语言中表示乘法
  15. # 如果将字符串和数字相乘,则解释器会将字符串重复指定的次数并返回
  16. a = a * 20
  17. print(a)

3.空值和布尔值

  1. # 布尔值(bool)
  2. # 布尔值主要用来做逻辑判断
  3. # 布尔值一共有两个 True 和 False
  4. # True表示真 False表示假
  5. a = True
  6. a = False
  7. # print('a =',a)
  8. # 布尔值实际上也属于整型,True就相当于1,False就相当于0
  9. # print(1 + False)
  10. # None(空值)
  11. # None专门用来表示不存在
  12. b = None
  13. print(b)

类型检查

  1. # 通过类型检查,可以检查只能值(变量)的类型
  2. a = 123 # 数值
  3. b = '123' # 字符串
  4. # print('a =',a)
  5. # print('b =',b)、
  6. # type()用来检查值的类型
  7. # 该函数会将检查的结果作为返回值返回,可以通过变量来接收函数的返回值
  8. c = type('123')
  9. c = type(a)
  10. # print(type(b))
  11. print(type(1)) # <class 'int'>
  12. print(type(1.5)) # <class 'float'>
  13. print(type(True)) # <class 'bool'>
  14. print(type('hello')) # <class 'str'>
  15. print(type(None)) # <class 'NoneType'>

对象(object)

  • Python是一门面向对象的语言
  • 一切皆对象!
  • 程序运行当中,所有的数据都是存储到内存当中然后再运行的!
  • 对象就是内存中专门用来存储指定数据的一块区域
  • 对象实际上就是一个容器,专门用来存储数据
  • 像我们之前学习的数值、字符串、布尔值、None都是对象

对象的结构

  • 每个对象中都要保存三种数据
    • id(标识)

      id用来标识对象的唯一性,每一个对象都有唯一的id
      对象的id就相当于人的身份证号一样
      可以通过id()函数来查看对象的id
      id是由解析器生成的,在CPython中,id就是对象的内存地址
      对象一旦创建,则它的id永远不能再改变

  • type(类型)

    类型用来标识当前对象所属的类型
    比如:int str float bool 。。。
    类型决定了对象有哪些功能
    通过type()函数来查看对象的类型
    Python是一门强类型的语言,对象一旦创建类型便不能修改

  • value(值)

    值就是对象中存储的具体的数据
    对于有些对象值是可以改变的
    对象分成两大类,可变对象 不可变对象
    可变对象的值可以改变
    不可变对象的值不能改变,之前学习的对象都是不可变对象

变量和对象

  • 对象并没有直接存储到变量中,在Python中变量更像是给对象起了一个别名
  • 变量中存储的不是对象的值,而是对象的id(内存地址),
    当我们使用变量时,实际上就是在通过对象id在查找对象
  • 变量中保存的对象,只有在为变量重新赋值时才会改变
  • 变量和变量之间是相互独立的,修改一个变量不会影响另一个变量

类型转换

  • 所谓的类型转换,将一个类型的对象转换为其他对象
  • 类型转换不是改变对象本身的类型,而是根据当前对象的值创建一个新对象
  1. # 类型转换四个函数 int() float() str() bool()
  2. # int() 可以用来将其他的对象转换为整型
  3. # 规则:
  4. # 布尔值:True -> 1 False -> 0
  5. # 浮点数:直接取整,省略小数点后的内容
  6. # 字符串:合法的整数字符串,直接转换为对应的数字
  7. # 如果不是一个合法的整数字符串,则报错 ValueError: invalid literal for int() with base 10: '11.5'
  8. # 对于其他不可转换为整型的对象,直接抛出异常 ValueError
  9. # float() 和 int()基本一致,不同的是它会将对象转换为浮点数
  10. # str() 可以将对象转换为字符串
  11. # True -> 'True'
  12. # False -> 'False'
  13. # 123 -> '123'
  14. # 。。。
  15. # bool() 可以将对象转换为布尔值,任何对象都可以转换为布尔值
  16. # 规则:对于所有表示空性的对象都会转换为False,其余的转换为True
  17. # 哪些表示的空性:0 、 None 、 '' 。。。
  18. a = True
  19. # 调用int()来将a转换为整型
  20. # int()函数不会对原来的变量产生影响,他是对象转换为指定的类型并将其作为返回值返回
  21. # 如果希望修改原来的变量,则需要对变量进行重新赋值
  22. a = int(a)
  23. a = False
  24. a = int(a)
  25. a = '123'
  26. a = int(a)
  27. a = 11.6
  28. a = int(a)
  29. a = '11.5'
  30. # a = int(a)
  31. a = None
  32. # a = int(a)
  33. a = 1
  34. a = float(a)
  35. a = False
  36. a = float(a)
  37. a = 123
  38. a = str(a)
  39. a = None
  40. a = bool(a)
  41. print('a =',a)
  42. print('a的类型是',type(a))
  43. # b = 456
  44. # print('hello'+str(b))

运算符(操作符)

  • 运算符可以对一个值或多个值进行运算或各种操作
  • 比如 + 、-、= 都属于运算符

运算符的分类:

1.算术运算符
  1. # 算术运算符
  2. # + 加法运算符(如果是两个字符串之间进行加法运算,则会进行拼串操作)
  3. # - 减法运算符
  4. # * 乘法运算符(如果将字符串和数字相乘,则会对字符串进行复制操作,将字符串重复指定次数)
  5. # / 除法运算符,运算时结果总会返回一个浮点类型
  6. # // 整除,只会保留计算后的整数位,总会返回一个整型
  7. # ** 幂运算,求一个值的几次幂
  8. # % 取模,求两个数相除的余数
  9. a = 10 + 5 # 计算
  10. a = 'hello' + ' ' + 'world' # 拼串
  11. a = 10 - 5 # 计算
  12. a = 5 - True
  13. a = a - 2 # 用变量a的值减去2,然后再赋值给a
  14. # a = 'hello' - 'h' TypeError
  15. a = 5 * 5
  16. a = 10 / 5
  17. a = 5 / 2
  18. # a = 5 / 0 ZeroDivisionError: division by zero
  19. a = 10 / 3
  20. a = 10 // 3
  21. a = 5 // 2
  22. a = 2 ** 2
  23. a = 10 ** 5
  24. a = 16 ** 0.5 # 求16的平方根
  25. a = 10 % 5 # 0
  26. a = 10 % 4 # 2
  27. a = 10 % 3 # 1
  28. a = 10 % 2 # 0
  29. print("a =",a)

2.赋值运算符
  1. # 赋值运算符
  2. # = 可以将等号右侧的值赋值给等号左侧的变量
  3. # += a += 5 相当于 a = a + 5
  4. # -= a -= 5 相当于 a = a - 5
  5. # *= a *= 5 相当于 a = a * 5
  6. # **= a **= 5 相当于 a = a ** 5
  7. # /= a /= 5 相当于 a = a / 5
  8. # //= a //= 5 相当于 a = a // 5
  9. # %= a %= 5 相当于 a = a % 5
  10. a = 10
  11. # a = a + 5
  12. # a += 5
  13. a -= 5
  14. a *= 5
  15. a **= 2
  16. a /= 25
  17. a = 25.0 # 在对浮点数做算术运算时,结果也会返回一个浮点数
  18. a //= 5
  19. a = 5
  20. a %= 4
  21. print('a =',a)

3.比较运算符(关系运算符)
  1. # 关系运算符
  2. # 关系运算符用来比较两个值之间的关系,总会返回一个布尔值
  3. # 如果关系成立,返回True,否则返回False
  4. # > 比较左侧值是否大于右侧值
  5. # >= 比较左侧的值是否大于或等于右侧的值
  6. # < 比较左侧值是否小于右侧值
  7. # <= 比较左侧的值是否小于或等于右侧的值
  8. # == 比较两个对象的值是否相等
  9. # != 比较两个对象的值是否不相等
  10. # 相等和不等比较的是对象的值,而不是id
  11. # is 比较两个对象是否是同一个对象,比较的是对象的id
  12. # is not 比较两个对象是否不是同一个对象,比较的是对象的id
  13. result = 10 > 20 # False
  14. result = 30 > 20 # True
  15. result = 30 < 20 # False
  16. result = 10 >= 10 # True
  17. result = 2 > True # True
  18. # result = 2 > '1' TypeError: '>' not supported between instances of 'int' and 'str'
  19. # 0032 > 0031
  20. result = '2' > '1' # True
  21. result = '2' > '11' # True
  22. # 在Python中可以对两个字符串进行大于(等于)或小于(等于)的运算,
  23. # 当对字符串进行比较时,实际上比较的是字符串的Unicode编码
  24. # 比较两个字符串的Unicode编码时,是逐位比较的
  25. # 利用该特性可以对字符串按照字母顺序进行排序,但是对于中文来说意义不是特别大
  26. # 注意:如果不希望比较两个字符串的Unicode编码,则需要将其转换为数字然后再比较
  27. # 0061 > 0062
  28. result = 'a' > 'b' # False
  29. result = 'c' < 'd' # True
  30. result = 'ab' > 'b' # False
  31. # print(int('2') > int('11'))
  32. result = 1 == 1 # True
  33. result = 'hello' == 'hello' # True
  34. result = 'abc' == 'bcd' # False
  35. result = 'abc' != 'bcd' # True
  36. result = 1 == True # True
  37. result = 1 is True # False
  38. result = 1 is not True # True
  39. print('result =',result)
  40. print(id(1),id(True))

4.逻辑运算符
  1. # 逻辑运算符
  2. # 逻辑运算符主要用来做一些逻辑判断
  3. # not 逻辑非
  4. # not可以对符号右侧的值进行非运算
  5. # 对于布尔值,非运算会对其进行取反操作,True变False,False变True
  6. # 对于非布尔值,非运算会先将其转换为布尔值,然后再取反
  7. #
  8. # and 逻辑与
  9. # and可以对符号两侧的值进行与运算
  10. # 只有在符号两侧的值都为True时,才会返回True,只要有一个False就返回False
  11. # 与运算是找False的
  12. # Python中的与运算是短路的与,如果第一个值为False,则不再看第二个值
  13. #
  14. # or 逻辑或
  15. # or 可以对符号两侧的值进行或运算
  16. # 或运算两个值中只要有一个True,就会返回True
  17. # 或运算是找True的
  18. # Python中的或运算是短路的或,如果第一个值为True,则不再看第二个值
  19. #
  20. # 练习:
  21. # 尝试一下对布尔值进行三种逻辑运算
  22. # 尝试对非布尔值进行三种逻辑运算,并观察返回的结果
  23. #
  24. a = True
  25. a = not a # 对a进行非运算
  26. a = 1
  27. a = ''
  28. a = not a
  29. # print('a =',a)
  30. result = True and True # True
  31. result = True and False # False
  32. result = False and True # False
  33. result = False and False # False
  34. # print(result)
  35. # True and print('你猜我出来吗?') 第一个值是True,会看第二个值,所以print()会执行
  36. # False and print('你猜我出来吗?')第一个值是False,不会看第二个值,所以print()不会执行
  37. result = True or True # True
  38. result = True or False # True
  39. result = False or True # True
  40. result = False or False # False
  41. # print(result)
  42. # False or print('你猜我出来吗?') 第一个值为False,继续看第二个,所以打印语句执行
  43. # True or print('你猜我出来吗?') 第一个值为True,不看第二个,所以打印语句不执行
  44. # 非布尔值的与或运算
  45. # 当我们对非布尔值进行与或运算时,Python会将其当做布尔值运算,最终会返回原值
  46. # 与运算的规则
  47. # 与运算是找False的,如果第一个值是False,则不看第二个值
  48. # 如果第一个值是False,则直接返回第一个值,否则返回第二个值
  49. # 或运算的规则
  50. # 或运算是找True的,如果第一个值是True,则不看第二个值
  51. # 如果第一个值是True,则直接返回第一个值,否则返回第二个值
  52. # True and True
  53. result = 1 and 2 # 2
  54. # True and False
  55. result = 1 and 0 # 0
  56. # False and True
  57. result = 0 and 1 # 0
  58. # False and False
  59. result = 0 and None # 0
  60. # True or True
  61. result = 1 or 2 # 1
  62. # True or False
  63. result = 1 or 0 # 1
  64. # False or True
  65. result = 0 or 1 # 1
  66. # False or False
  67. result = 0 or None # None
  68. print(result)

5.条件运算符(三元运算符)
  1. # 条件运算符(三元运算符)
  2. # 语法: 语句1 if 条件表达式 else 语句2
  3. # 执行流程:
  4. # 条件运算符在执行时,会先对条件表达式进行求值判断
  5. # 如果判断结果为True,则执行语句1,并返回执行结果
  6. # 如果判断结果为False,则执行语句2,并返回执行结果
  7. # 练习:
  8. # 现在有a b c三个变量,三个变量中分别保存有三个数值,
  9. # 请通过条件运算符获取三个值中的最大值
  10. # print('你好') if False else print('Hello')
  11. a = 30
  12. b = 50
  13. # print('a的值比较大!') if a > b else print('b的值比较大!')
  14. # 获取a和b之间的较大值
  15. max = a if a > b else b
  16. print(max)

运算符的优先级

  1. a = 40
  2. b = 50
  3. c = 30
  4. # 通过条件运算符获取三个值中的最大值
  5. # max = a if a > b else b
  6. # max = max if max > c else c
  7. max = a if (a > b and a > c) else (b if b > c else c) # 不推荐这么使用
  8. # max = a if (b < a > c) else (b if b > c else c)
  9. # print(max)
  10. # 运算符的优先级
  11. # 和数学中一样,在Python运算也有优先级,比如先乘除 后加减
  12. # 运算符的优先级可以根据优先级的表格来查询,
  13. # 在表格中位置越靠下的运算符优先级越高,优先级越高的越优先计算
  14. # 如果优先级一样则自左向右计算
  15. # 关于优先级的表格,你知道有这么一个东西就够了,千万不要去记
  16. # 在开发中如果遇到优先级不清楚的,则可以通过小括号来改变运算顺序
  17. a = 1 + 2 * 3
  18. # 一样 and高 or高
  19. # 如果or的优先级高,或者两个运算符的优先级一样高
  20. # 则需要先进行或运算,则运算结果是3
  21. # 如果and的优先级高,则应该先计算与运算
  22. # 则运算结果是1
  23. a = 1 or 2 and 3
  24. # print(a)
  25. # 逻辑运算符(补充)
  26. # 逻辑运算符可以连着使用
  27. result = 1 < 2 < 3 # 相当于 1 < 2 and 2 < 3
  28. result = 10 < 20 > 15
  29. print(result)

第三部分 流程控制语句

Python代码在执行时是按照自上向下顺序执行的。通过流程控制语句,可以改变程序的执行顺序,也可以让指定的程序反复执行多次
流程控制语句分成两大类:条件判断语句,循环语句

条件判断语句(if语句)

if语句

  1. # 条件判断语句(if语句)
  2. # 语法:if 条件表达式 :
  3. # 代码块
  4. # 执行的流程:if语句在执行时,会先对条件表达式进行求值判断,
  5. # 如果为True,则执行if后的语句
  6. # 如果为False,则不执行
  7. # 默认情况下,if语句只会控制紧随其后的那条语句,如果希望if可以控制多条语句,
  8. # 则可以在if后跟着一个代码块
  9. # 代码块
  10. # 代码块中保存着一组代码,同一个代码块中的代码,要么都执行要么都不执行
  11. # 代码块就是一种为代码分组的机制
  12. # 如果要编写代码块,语句就不能紧随在:后边,而是要写在下一行
  13. # 代码块以缩进开始,直到代码恢复到之前的缩进级别时结束
  14. # 鲁迅说过:
  15. # 世上本来没有路,走的人多了自然就有了!
  16. # xxxx
  17. # yyyy....
  18. # 缩进有两种方式,一种是使用tab键,一种是使用空格(四个)
  19. # Python的官方文档中推荐我们使用空格来缩进
  20. # Python代码中使用的缩进方式必须统一
  21. # "translate_tabs_to_spaces": true,
  22. # if False : print('你猜我出来么?')
  23. num = 10
  24. # if num > 10 : print('num比10大!')
  25. # print('谁也管不了我')
  26. if False :
  27. print(123)
  28. print(456)
  29. print(789)
  30. print(101112)
  31. # print('hello')
  32. num = 28
  33. # 可以使用逻辑运算符来连接多个条件,
  34. # 如果希望所有条件同时满足,则需要使用and
  35. # 如果希望只要有一个条件满足即可,则需要使用or
  36. # if num > 10 and num < 20 :
  37. # print('num比10大,num比20小!')
  38. # if 10 < num < 20 :
  39. # print('num比10大,num比20小!')
  40. # 在命令行让用户输入一个用户名,获取用户输入,并进行判断
  41. # 如果用户输入的用户名是admin,则显示欢迎管理员光临
  42. # 如果用户输入的是其他的用户名,则什么也不做
  43. username=input("输入用户名")
  44. if username=="admin":
  45. print("欢迎管理员光临")

input函数

  1. # input()函数
  2. # 该函数用来获取用户的输入
  3. # input()调用后,程序会立即暂停,等待用户输入
  4. # 用户输入完内容以后,点击回车程序才会继续向下执行
  5. # 用户输入完成以后,其所输入的的内容会以返回值得形式返回
  6. # 注意:input()的返回值是一个字符串
  7. # input()函数中可以设置一个字符串作为参数,这个字符串将会作为提示文字显示
  8. # a = input('请输入任意内容:')
  9. # print('用户输入的内容是:',a)
  10. # input()也可以用于暂时阻止程序结束
  11. # 获取用户输入的用户名
  12. username = input('请输入你的用户名:')
  13. # 判断用户名是否是admin
  14. if username == 'admin' :
  15. print('欢迎管理员光临!')

if-else语句

  1. 让用户在控制台中输入一个年龄
  2. # age = int(input('请输入你的年龄:'))
  3. # 如果用户的年龄大于18岁,则显示你已经成年了
  4. # if age >= 18 :
  5. # print('你已经成年了~~~')
  6. # if-else语句
  7. # 语法:
  8. # if 条件表达式 :
  9. # 代码块
  10. # else :
  11. # 代码块
  12. # 执行流程:
  13. # if-else语句在执行时,先对if后的条件表达式进行求值判断
  14. # 如果为True,则执行if后的代码块
  15. # 如果为False,则执行else后的代码块
  16. age = 7
  17. if age > 17 :
  18. print('你已经成年了~~')
  19. else :
  20. print('你还未成年~~')

if-elif-else语句

  1. # if-elif-else语句
  2. # 语法:
  3. # if 条件表达式 :
  4. # 代码块
  5. # elif 条件表达式 :
  6. # 代码块
  7. # elif 条件表达式 :
  8. # 代码块
  9. # elif 条件表达式 :
  10. # 代码块
  11. # else :
  12. # 代码块
  13. #
  14. # 执行流程:
  15. # if-elif-else语句在执行时,会自上向下依次对条件表达式进行求值判断,
  16. # 如果表达式的结果为True,则执行当前代码块,然后语句结束
  17. # 如果表达式的结果为False,则继续向下判断,直到找到True为止
  18. # 如果所有的表达式都是False,则执行else后的代码块
  19. # if-elif-else中只会有一个代码块会执行
  20. age = 210
  21. # if age > 200 :
  22. # print('活着可真没劲呢!')
  23. # elif age > 100 :
  24. # print('你也是老大不小了!')
  25. # elif age >= 60 :
  26. # print('你已经退休了!')
  27. # elif age >= 30 :
  28. # print('你已经是中年了!')
  29. # elif age >= 18 :
  30. # print('你已经成年了!')
  31. # else :
  32. # print('你还是个小孩!')
  33. age = 68
  34. if age >= 18 and age < 30 :
  35. print('你已经成年了!')
  36. elif age >= 30 and age < 60 :
  37. print('你已经中年了!')
  38. elif age >= 60 :
  39. print('你已经退休了!')

练习

练习1:
  1. 编写一个程序,获取一个用户输入的整数。然后通过程序显示这个数是奇数还是偶数。
  1. from cgi import print_form
  2. enter_an_integer = int(input('输入一个整数:'))
  3. print('你输入的整数是:',enter_an_integer)
  4. if enter_an_integer % 2 == 0:
  5. print('这个数是偶数')
  6. if enter_an_integer % 2 == 1:
  7. print('这个数是奇数')
  8. # 优化:
  9. # 获取用户输入的整数
  10. # num = int(input('请输入一个任意的整数:'))
  11. # print('你输入的整数是:',enter_an_integer)
  12. # # 显示num是奇数还是偶数
  13. # if num % 2 == 0 :
  14. # print(num , "是偶数")
  15. # else :
  16. # print(num , '是奇数')

练习2:
  1. 编写一个程序,检查任意一个年份是否是闰年。<br /> 如果一个年份可以被4整除不能被100整除,或者可以被400整除,这个年份就是闰年
  1. year = int(input('输入一个年份'))
  2. #print('你输入的是',year)
  3. if year % 4 == 0 and year %100!=0 or year %400 == 0:
  4. print('这个年份是闰年')
  5. else:
  6. print('这个年份不是闰年')

练习3:
  1. 我家的狗5岁了,5岁的狗相当于多大年龄的人呢?<br /> 其实非常简单,狗的前两年每一年相当于人类的10.5岁,然后每增加一年就增加四岁。<br /> 那么5岁的狗相等于人类的年龄就应该是10.5+10.5+4+4+4 = 33岁<br /> 编写一个程序,获取用户输入的狗的年龄,然后通过程序显示其相当于人类的年龄。<br /> 如果用户输入负数,请显示一个提示信息
  1. dog_age = float(input('请输入狗的年龄:'))
  2. print('狗的年龄是:',dog_age)
  3. if dog_age < 0 :
  4. print('你输入的',dog_age,'不是正确的年龄')
  5. elif dog_age <= 2 :
  6. dog_age = 10.5
  7. print('狗的年龄是:',dog_age)
  8. else :
  9. dog_age = 21+(dog_age-2)*4
  10. print('狗的年龄是',dog_age)
  11. # 优化解答
  12. # dog_age = float(input('请输入狗的年龄:'))
  13. # like_person_age = 0
  14. # 检查用户输入的是否是负数
  15. # if dog_age < 0 :
  16. # print('你的输入不合法!')
  17. # # 如果狗的年龄在两岁以下(包含两岁)
  18. # elif dog_age <= 2 :
  19. # # 直接将当前的年龄乘以10.5
  20. # like_person_age = dog_age * 10.5
  21. # # 如果狗的年龄在两岁以上
  22. # else :
  23. # # 计算前两岁相当于人类的年纪
  24. # like_person_age = 2 * 10.5
  25. # # 计算超过两岁的部分相对于人类的年纪,并进行相加
  26. # like_person_age += ( dog_age - 2 ) * 4
  27. # if dog_age > 0 :
  28. # print(dog_age,'岁的狗,年纪相当于',like_person_age,'岁的人')
  29. #
  30. # 在if也可以去嵌套if,代码块是可以嵌套的,每增加一个缩进的级别,代码块就低一级
  31. # 检查用户的输入是否合法
  32. # if dog_age > 0 :
  33. # # 如果狗的年龄在两岁以下(包含两岁)
  34. # if dog_age <= 2 :
  35. # # 直接将当前的年龄乘以10.5
  36. # like_person_age = dog_age * 10.5
  37. # # 如果狗的年龄在两岁以上
  38. # else :
  39. # # 计算前两岁相当于人类的年纪
  40. # like_person_age = 2 * 10.5
  41. # # 计算超过两岁的部分相对于人类的年纪,并进行相加
  42. # like_person_age += ( dog_age - 2 ) * 4
  43. # print(dog_age,'岁的狗,年纪相当于',like_person_age,'岁的人')
  44. # else :
  45. # print('请输入一个合法的年龄!')

练习4:
  1. 从键盘输入小明的期末成绩:<br /> 当成绩为100时,'奖励一辆BMW'<br /> 当成绩为[80-99]时,'奖励一台iphone'<br /> 当成绩为[60-79]时,'奖励一本参考书'<br /> 其他时,什么奖励也没有
  1. final_result = float(input('请输入期末成绩:'))
  2. print('你的期末成绩是:',final_result)
  3. if final_result == 100 :
  4. print('奖励一辆BMW')
  5. elif final_result >= 80 and final_result<=99 :
  6. print('奖励一台iphone')
  7. elif final_result >= 60 and final_result <= 79 :
  8. print('奖励一本参考书')
  9. else :
  10. print('没有奖励')
  11. # 优化结果
  12. # 获取小明的成绩
  13. # score = float(input('请输入你的期末成绩(0-100):'))
  14. # # 打印分割线
  15. # print("="*40)
  16. # # 检查用户的输入是否合法
  17. # if 0 <= score <= 100 :
  18. # # 判断发给的奖励
  19. # if score == 100 :
  20. # print('宝马,拿去玩!')
  21. # elif score >= 80 :
  22. # print('苹果手机,拿去玩!')
  23. # elif score >= 60 :
  24. # print('参考书,拿去玩!')
  25. # else :
  26. # print('棍子一根!')
  27. # else :
  28. # # 用户输入的不合法,弹出一个友好提示
  29. # print('你输入的内容不合法,拉出去毙了!')

练习5:
  1. 大家都知道,男大当婚,女大当嫁。那么女方家长要嫁女儿,当然要提出一定的条件:<br /> 高:180cm以上; 富:1000万以上; 帅:500以上;<br /> 如果这三个条件同时满足,则:'我一定要嫁给他'<br /> 如果三个条件有为真的情况,则:'嫁吧,比上不足,比下有余。'<br /> 如果三个条件都不满足,则:'不嫁!'
  1. height = float(input('请输入身高(0-300)c:'))
  2. wealth = float(input('请输入财富xxx万元:'))
  3. face= float(input('请输入颜值(0-800)cm:'))
  4. if height > 180 and wealth > 1000 and face > 500:
  5. print('我一定要嫁给他')
  6. elif height > 180 or wealth >1000 or height > 180 :
  7. print('嫁吧,比上不足,比下有余。')
  8. else:
  9. print('不嫁!')

循环语句

循环语句可以使指定的代码块重复指定的次数
循环语句分成两种,while循环 和 for循环

while循环

  1. # while循环
  2. # 语法:
  3. # while 条件表达式 :
  4. # 代码块
  5. # else :
  6. # 代码块
  7. # 执行流程:
  8. # while语句在执行时,会先对while后的条件表达式进行求值判断,
  9. # 如果判断结果为True,则执行循环体(代码块),
  10. # 循环体执行完毕,继续对条件表达式进行求值判断,以此类推,
  11. # 直到判断结果为False,则循环终止,如果循环有对应的else,则执行else后的代码块
  12. # 条件表达式恒为True的循环语句,称为死循环,它会一直运行,慎用!
  13. # while True :
  14. # print('hello')
  15. # 循环的三个要件(表达式)
  16. # 初始化表达式,通过初始化表达式初始化一个变量
  17. # i = 0
  18. # # 条件表达式,条件表达式用来设置循环执行的条件
  19. # while i < 10 :
  20. # print(i)
  21. # # 更新表达式,修改初始化变量的值
  22. # i += 1
  23. # 创建一个执行十次的循环
  24. i = 0
  25. while i < 10 :
  26. i += 1
  27. print(i,'hello')
  28. else :
  29. print('else中的代码块')

break \ continue \ pass

break:
可以用来立即退出循环语句(包括else)

continue:
可以用来跳过当次循环
break和continue都是只对离他最近的循环起作用

pass:
是用来在判断或循环语句中占位的

  1. 例子:
  2. # 创建一个5次的循环
  3. i = 0
  4. while i < 5:
  5. if i == 3:
  6. break
  7. print(i)
  8. i += 1
  9. else :
  10. print('循环结束')
  11. # i = 0
  12. # while i < 5:
  13. # i += 1
  14. # if i == 2:
  15. # continue
  16. # print(i)
  17. # else :
  18. # print('循环结束')
  19. i = 0
  20. if i < 5:
  21. pass

练习

练习1:求100以内所有的奇数之和
  1. 100以内所有的奇数之和
  1. # 求100以内所有的奇数之和
  2. result = 0
  3. i = 0
  4. while i <= 100 :
  5. i += 1
  6. if i % 2 == 1 :
  7. result = result + i
  8. print("100以内所有奇数和为:",result)
  9. #优化
  10. # 获取所有100以内数
  11. # i = 0
  12. # # 创建一个变量,用来保存结果
  13. # result = 0
  14. # while i < 100 :
  15. # i += 1
  16. # # 判断i是否是奇数
  17. # if i % 2 != 0:
  18. # result += i
  19. # print('result =',result)

练习2: 求100以内所有7的倍数之和,以及个数
  1. 100以内所有7的倍数之和,以及个数
  1. # 求100以内所有7的倍数之和,以及个数
  2. result = 0
  3. i = 7
  4. count = 0
  5. while i < 100:
  6. count += 1
  7. i += 7
  8. result = result + i
  9. print('result=',result)
  10. print('j=',count)
  11. #优化结果
  12. # 求100以内所有7的倍数之和,以及个数
  13. # i = 7
  14. # 创建一个变量,来保存结果
  15. # result = 0
  16. # 创建一个计数器,用来记录循环执行的次数
  17. # 计数器就是一个变量,专门用来记录次数的变量
  18. # count = 0
  19. # while i < 100:
  20. # 为计数器加1
  21. # count += 1
  22. # result += i
  23. # i += 7
  24. # print('总和为:',result,'总数量为:',count)

练习3:求1000以内所有的水仙花数
  1. 水仙花数是指一个 n 位数(n3 ),它的每个位上的数字的 n 次幂之和等于它本身(例如:1**3 + 5**3 + 3**3 = 153)。<br /> 1000以内所有的水仙花数
  1. # 获取1000以内的三位数
  2. i = 100
  3. while i < 1000:
  4. # 假设,i的百位数是a,十位数b,个位数c
  5. # 求i的百位数
  6. a = i // 100
  7. # 求i的十位数
  8. # b = i // 10 % 10
  9. b = (i - a * 100) // 10
  10. # 求i的个位数字
  11. c = i % 10
  12. # print(i , a , b , c)
  13. # 判断i是否是水仙花数
  14. if a**3 + b**3 + c**3 == i :
  15. print(i)
  16. i += 1

练习4:判断是否是质数
  1. 获取用户输入的任意数,判断其是否是质数。质数是只能被1和它自身整除的数,1不是质数也不是合数。
  1. # 获取用户输入的任意数,判断其是否是质数。
  2. num = int(input('输入一个任意的大于1的整数:'))
  3. # 判断num是否是质数,只能被1和它自身整除的数就是质数
  4. # 获取到所有的可能整除num的整数
  5. i = 2
  6. # 创建一个变量,用来记录num是否是质数,默认认为num是质数
  7. flag = True
  8. while i < num:
  9. # 判断num能否被i整除
  10. # 如果num能被i整除,则说明num一定不是质
  11. if num % i == 0 :
  12. # 一旦进入判断,则证明num不是质数,则需要将flag修改为false
  13. flag = False
  14. i += 1
  15. if flag :
  16. print(num,'是质数')
  17. else :
  18. print(num,'不是质数')

循环嵌套

  1. # 在控制台中打印如下图形
  2. # *****
  3. # *****
  4. # *****
  5. # *****
  6. # *****
  7. #
  8. # 创建一个循环来控制图形的高度
  9. # 循环嵌套时,外层循环没执行一次,内存循环就要执行一圈
  10. # i = 0
  11. # while i < 5:
  12. # # 创建一个内层循环来控制图形的宽度
  13. # j = 0
  14. # while j < 5:
  15. # print("* ",end='')
  16. # j += 1
  17. # print()
  18. # i += 1
  19. #
  20. # * j<1 i=0
  21. # ** j<2 i=1
  22. # *** j<3 i=2
  23. # **** j<4 i=3
  24. # ***** j<5 i=4
  25. #
  26. # *****
  27. # ****
  28. # ***
  29. # **
  30. # *
  31. i = 0
  32. while i < 5:
  33. j = 0
  34. while j < i + 1:
  35. print("* ",end='')#这里的end=''是为了使print输出内容不换行
  36. j += 1
  37. print()
  38. i += 1

练习

练习1: 打印99乘法表
  1. 打印99乘法表<br /> 1*1=1<br /> 1_2=2 2_2=4<br /> 1_3=3 2_3=6 3*3=9<br /> ... 9*9=81
  1. # 创建一个外层循环来控制图形的高度
  2. i = 0
  3. while i < 9:
  4. i += 1
  5. # 创建一个内层循环来控制图形的宽度
  6. j = 0
  7. while j < i:
  8. j += 1
  9. print(f"{j}*{i}={i*j} ",end="")
  10. print()

练习2:求100以内所有的质数
  1. 100以内所有的质数
  1. # 求100以内所有的质数
  2. # 创建一个循环,求1-100以内所有的数
  3. i = 2
  4. while i <= 100:
  5. # 创建一个变量,记录i的状态,默认认为i是质数
  6. flag = True
  7. # 判断i是否是质数
  8. # 获取所有可能成为i的因数的数
  9. j = 2
  10. while j < i:
  11. # 判断i能否被j整除
  12. if i % j == 0:
  13. # i能被j整除,证明i不是质数,修改flag为False
  14. flag = False
  15. j += 1
  16. # 验证结果并输出
  17. if flag :
  18. print(i)
  19. i += 1

练习优化示例:模块的引入

模块,通过模块可以对Python进行扩展
引入一个time模块,来统计程序执行的时间。time()函数可以用来获取当前的时间,返回的单位是秒

优化前:
求100000以内所有的质数

  1. from time import *
  2. begin = time()
  3. i = 2
  4. while i <= 10000:
  5. flag = True
  6. j = 2
  7. while j < i:
  8. if i % j == 0:
  9. flag = False
  10. j += 1
  11. if flag :
  12. #print(i)
  13. i += 1
  14. end = time()
  15. print("程序执行花费了:",end - begin , "秒")

结果:程序执行花费了: 8.352874279022217 秒

第一次优化:

  1. from time import *
  2. # 获取程序开始的时间
  3. begin = time()
  4. i = 2
  5. while i <= 10000:
  6. flag = True
  7. j = 2
  8. while j < i:
  9. if i % j == 0:
  10. flag = False
  11. # 一旦进入判断,则证明i一定不是质数,此时内层循环没有继续执行的必要
  12. # 使用break来退出内层的循环
  13. break
  14. j += 1
  15. if flag :
  16. # print(i)
  17. pass
  18. i += 1
  19. # 获取程序结束的时间
  20. end = time()
  21. # 计算程序执行的时间
  22. print("程序执行花费了:",end - begin , "秒")

结果:程序执行花费了: 0.9832208156585693 秒

第二次优化:

算法优化:一个数的因数最大是其本身的算术平方根

  1. from time import *
  2. begin = time()
  3. i = 2
  4. while i <= 10000:
  5. flag = True
  6. j = 2
  7. while j <= i ** 0.5:#这里进行优化
  8. if i % j == 0:
  9. flag = False
  10. break
  11. j += 1
  12. if flag :
  13. # print(i)
  14. pass
  15. i += 1
  16. end = time()
  17. print("程序执行花费了:",end - begin , "秒")

结果: 程序执行花费了: 0.040992021560668945 秒

可见优化程序对提高程序运行效率十分重要。

总练习 小游戏

小游戏 《唐僧大战白骨精》

内容:

  1. 1、身份选择
  2. 显示提示信息
  3. 欢迎光临 xxx 游戏!
  4. 请选择你的身份:
  5. 1.xxx
  6. 2.xxx
  7. 请选择:x
  8. 根据用户选择来分配身份(显示不同的提示消息)
  9. 1.---
  10. 2.---
  11. 3.---
  12. 2、游戏进行
  13. 显示玩家的基本信息(攻击力 生命值)
  14. 显示玩家可以进行的操作:
  15. 1、练级
  16. - 提升玩家的攻击力和生命值
  17. 2、打BOSS
  18. - 玩家对BOSS进行攻击,玩家要攻击BOSSBOSS对玩家进行反击
  19. - 计算BOSS是否被玩家消灭,玩家是否被BOSS消灭
  20. - 游戏结束
  21. 3、逃跑
  22. - 退出游戏,显示提示信息,游戏结束!

代码:

  1. # 显示欢迎信息
  2. print('-'*20,'欢迎光临《唐僧大战白骨精》','-'*20)
  3. # 显示身份选择的信息
  4. print('请选择你的身份:')
  5. print('\t1.唐僧')
  6. print('\t2.白骨精')
  7. # 游戏的身份选择
  8. player_choose = input('请选择[1-2]:')
  9. # 打印一条分割线
  10. print('-'*66)
  11. # 根据用户的选择来显示不同的提示信息
  12. if player_choose == '1':
  13. # 选择1
  14. print('你已经选择了1,你将以->唐僧<-的身份来进行游戏!')
  15. elif player_choose == '2':
  16. # 选择2
  17. print('你竟然选择了白骨精,太不要脸了,你将以->唐僧<-的身份来进行游戏!')
  18. else :
  19. # 选择3
  20. print('你的输入有误,系统将自动分配身份,你将以->唐僧<-的身份来进行游戏!')
  21. # 进入游戏
  22. # 创建变量,来保存玩家的生命值和攻击力
  23. player_life = 2 # 生命值
  24. player_attack = 2 # 攻击力
  25. # 创建一个变量,保存boss的生命值和攻击力
  26. boss_life = 10
  27. boss_attack = 10
  28. # 打印一条分割线
  29. print('-'*66)
  30. # 显示玩家的信息(攻击力、生命值)
  31. print(f'唐僧,你的生命值是 {player_life} , 你的攻击力是 {player_attack}')
  32. # 由于游戏选项是需要反复显示的,所以必须将其编写到一个循环中
  33. while True :
  34. # 打印一条分割线
  35. print('-'*66)
  36. # 显示游戏选项,游戏正式开始
  37. print('请选择你要进行的操作:')
  38. print('\t1.练级')
  39. print('\t2.打BOSS')
  40. print('\t3.逃跑')
  41. game_choose = input('请选择要做的操作[1-3]:')
  42. # 处理用户的选择
  43. if game_choose == '1' :
  44. # 增加玩家的生命值和攻击力
  45. player_life += 2
  46. player_attack += 2
  47. # 显示最新的信息
  48. # 打印一条分割线
  49. print('-'*66)
  50. # 显示玩家的信息(攻击力、生命值)
  51. print(f'恭喜你升级了!,你现在的生命值是 {player_life} , 你的攻击力是 {player_attack}')
  52. elif game_choose == '2' :
  53. # 玩家攻击boss
  54. # 减去boss的生命值,减去的生命值应该等于玩家的攻击力
  55. boss_life -= player_attack
  56. # 打印一条分割线
  57. print('-'*66)
  58. print('->唐僧<- 攻击了 ->白骨精<-')
  59. # 检查boss是否死亡
  60. if boss_life <= 0 :
  61. # boss死亡,player胜利,游戏结束
  62. print(f'->白骨精<-受到了 {player_attack} 点伤害,重伤不治死了,->唐僧<-赢得了胜利!')
  63. # 游戏结束
  64. break
  65. # boss要反击玩家
  66. # 减去玩家的生命值
  67. player_life -= boss_attack
  68. print(' ->白骨精<- 攻击了 ->唐僧<-')
  69. # 检查玩家是否死亡
  70. if player_life <= 0 :
  71. # 玩家死亡
  72. print(f'你受到了 {boss_attack} 点伤害,重伤不治死了!GAME OVER')
  73. # 游戏结束
  74. break
  75. elif game_choose == '3' :
  76. # 打印一条分割线
  77. print('-'*66)
  78. # 逃跑,退出游戏
  79. print('->唐僧<-一扭头,撒腿就跑!GAME OVER')
  80. break
  81. else :
  82. # 打印一条分割线
  83. print('-'*66)
  84. print('你的输入有误,请重新输入!')

第四部分 序列

列表(list)

列表是Python中的一个对象
对象(object)就是内存中专门用来存储数据的一块区域,之前我们学习的对象,像数值,它只能保存一个单一的数据
列表中可以保存多个有序的数据,列表是用来存储对象的对象
列表的使用:
1.列表的创建
2.操作列表中的数据

列表的介绍

类似于C中的数组,但是更灵活

  1. # 创建列表,通过[]来创建列表
  2. my_list = [] # 创建了一个空列表
  3. # print(my_list , type(my_list))
  4. # 列表存储的数据,我们称为元素
  5. # 一个列表中可以存储多个元素,也可以在创建列表时,来指定列表中的元素
  6. my_list = [10] # 创建一个只包含一个元素的列表
  7. # 当向列表中添加多个元素时,多个元素之间使用,隔开
  8. my_list = [10,20,30,40,50] # 创建了一个包含有5个元素的列表
  9. # 列表中可以保存任意的对象
  10. my_list = [10,'hello',True,None,[1,2,3],print]
  11. # 列表中的对象都会按照插入的顺序存储到列表中,
  12. # 第一个插入的对象保存到第一个位置,第二个保存到第二个位置
  13. # 我们可以通过索引(index)来获取列表中的元素
  14. # 索引是元素在列表中的位置,列表中的每一个元素都有一个索引
  15. # 索引是从0开始的整数,列表第一个位置索引为0,第二个位置索引为1,第三个位置索引为2,以此类推
  16. my_list = [10,20,30,40,50]
  17. # 通过索引获取列表中的元素
  18. # 语法:my_list[索引] my_list[0]
  19. print(my_list[4])
  20. # 如果使用的索引超过了最大的范围,会抛出异常
  21. print(my_list[5]) IndexError: list index out of range
  22. # 获取列表的长度,列表中元素的个数
  23. # len()函数,通过该函数可以获取列表的长度
  24. # 获取到的长度的值,是列表的最大索引 + 1
  25. print(len(my_list)) # 5

列表的切片

切片指从现有列表中,获取一个子列表

  1. # 创建一个列表,一般创建列表时,变量的名字会使用复数
  2. stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
  3. # 列表的索引可以是负数
  4. # 如果索引是负数,则从后向前获取元素,-1表示倒数第一个,-2表示倒数第二个 以此类推
  5. print(stus[-2])
  6. # 通过切片来获取指定的元素
  7. # 语法:列表[起始:结束]
  8. # 通过切片获取元素时,会包括起始位置的元素,不会包括结束位置的元素
  9. # 做切片操作时,总会返回一个新的列表,不会影响原来的列表
  10. # 起始和结束位置的索引都可以省略不写
  11. # 如果省略结束位置,则会一直截取到最后
  12. # 如果省略起始位置,则会从第一个元素开始截取
  13. # 如果起始位置和结束位置全部省略,则相当于创建了一个列表的副本
  14. print(stus[1:])
  15. print(stus[:3])
  16. print(stus[:])#相当于创建副本
  17. print(stus)
  18. # 语法:列表[起始:结束:步长]
  19. # 步长表示,每次获取元素的间隔,默认值是1
  20. print(stus[0:5:3])
  21. # 步长不能是0,但是可以是负数
  22. print(stus[::0]) ValueError: slice step cannot be zero
  23. # 如果是负数,则会从列表的后部向前边取元素
  24. print(stus[::-1])

列表的通用操作

  1. # + 和 *
  2. # +可以将两个列表拼接为一个列表
  3. my_list = [1,2,3] + [4,5,6]
  4. # * 可以将列表重复指定的次数
  5. my_list = [1,2,3] * 5
  6. # print(my_list)
  7. # 创建一个列表
  8. stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精','沙和尚','沙和尚']
  9. # in 和 not in
  10. # in用来检查指定元素是否存在于列表中
  11. # 如果存在,返回True,否则返回False
  12. # not in用来检查指定元素是否不在列表中
  13. # 如果不在,返回True,否则返回False
  14. # print('牛魔王' not in stus)
  15. # print('牛魔王' in stus)
  16. # len()获取列表中的元素的个数
  17. # min() 获取列表中的最小值
  18. # max() 获取列表中的最大值
  19. arr = [10,1,2,5,100,77]
  20. # print(min(arr) , max(arr))
  21. # 两个方法(method),方法和函数基本上是一样,只不过方法必须通过 对象.方法() 的形式调用
  22. # xxx.print() 方法实际上就是和对象关系紧密的函数
  23. # s.index() 获取指定元素在列表中的第一次出现时的索引(的位置)
  24. # print(stus.index('沙和尚'))
  25. # index()的第二个参数,表示查找的起始位置 , 第三个参数,表示查找的结束位置
  26. # print(stus.index('沙和尚',3,7))
  27. # 如果要获取列表中没有的元素,会抛出异常
  28. # print(stus.index('牛魔王')) ValueError: '牛魔王' is not in list
  29. # s.count() 统计指定元素在列表中出现的次数
  30. print(stus.count('牛魔王'))

序列(sequence)

序列是Python中最基本的一种数据结构 (就是一种顺序表)

数据结构指计算机中数据存储的方式
序列用于保存一组有序的数据,所有的数据在序列当中都有一个唯一的位置(索引), 并且序列中的数据会按照添加的顺序来分配索引

序列的分类:
可变序列(序列中的元素可以改变):
列表(list)
不可变序列(序列中的元素不能改变):
字符串(str)
元组(tuple)

前面部分所写的所有操作都是序列的通用操作,是列表,字符串,元组三个文件中的操作

列表的修改

  1. # 创建一个列表
  2. stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
  3. # print("修改前:",stus)
  4. # 修改列表中的元素
  5. # 直接通过索引来修改元素
  6. stus[0] = 'sunwukong'
  7. stus[2] = '哈哈'
  8. # 通过del来删除元素
  9. del stus[2] # 删除索引为2的元素
  10. stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
  11. # 通过切片来修改列表
  12. # 在给切片进行赋值时,只能使用序列(等号两边都是序列)
  13. # stus[0:2] = ['牛魔王','红孩儿'] 使用新的元素替换旧元素
  14. # stus[0:2] = ['牛魔王','红孩儿','二郎神']
  15. # stus[0:0] = ['牛魔王'] # 向索引为0的位置插入元素
  16. # 当设置了步长时,序列中元素的个数必须和切片中元素的个数一致
  17. # stus[::2] = ['牛魔王','红孩儿','二郎神']
  18. # 通过切片来删除元素
  19. # del stus[0:2]
  20. # del stus[::2]
  21. # stus[1:3] = []
  22. # 以上操作,只适用于可变序列
  23. s = 'hello'
  24. # s[1] = 'a' 不可变序列,无法通过索引来修改
  25. # 可以通过 list() 函数将其他的序列转换为list
  26. s = list(s)
  27. print(s)

列表的方法(通过方法修改列表)

  1. # 列表的方法
  2. stus = ['孙悟空','猪八戒','沙和尚','唐僧']
  3. # print('原列表:',stus)
  4. # append()
  5. # 向列表的最后添加一个元素
  6. stus.append('唐僧')
  7. # insert()
  8. # 向列表的指定位置插入一个元素
  9. # 参数:
  10. # 1.要插入的位置
  11. # 2.要插入的元素
  12. stus.insert(2,'唐僧')
  13. # extend()
  14. # 使用新的序列来扩展当前序列
  15. # 需要一个序列作为参数,它会将该序列中的元素添加到当前列表中
  16. stus.extend(['唐僧','白骨精'])
  17. stus += ['唐僧','白骨精']
  18. #这两者的效果是一模一样的
  19. # clear()
  20. # 清空序列
  21. stus.clear()
  22. # pop()
  23. # 根据索引删除并返回被删除的元素
  24. result = stus.pop(2) # 删除索引为2的元素
  25. result = stus.pop() # 删除最后一个
  26. print('result =',result)
  27. # remove()
  28. # 删除指定值的元素,如果相同值得元素有多个,只会删除第一个
  29. stus.remove('猪八戒')
  30. # reverse()
  31. # 用来反转列表
  32. stus.reverse()
  33. # sort()
  34. # 用来对列表中的元素进行排序,默认是升序排列
  35. # 如果需要降序排列,则需要传递一个reverse=True作为参数
  36. my_list = list('asnbdnbasdabd')#这里是类型转换,将字符串转换为列表(字母按字母顺序进行排列)
  37. my_list = [10,1,20,3,4,5,0,-2]
  38. print('修改前',my_list)
  39. my_list.sort(reverse=True)#降序排列
  40. print('修改后',my_list)
  41. # print('修改后:',stus)

range()函数

range()是一个函数,可以用来生成一个自然数的序列

  1. # range()是一个函数,可以用来生成一个自然数的序列
  2. r = range(5) # 生成一个这样的序列[0,1,2,3,4]
  3. r = range(0,10,2)
  4. r = range(10,0,-1)
  5. # 该函数需要三个参数
  6. # 1.起始位置(可以省略,默认是0)
  7. # 2.结束位置
  8. # 3.步长(可以省略,默认是1)
  9. print(list(r))
  10. # 通过range()可以创建一个执行指定次数的for循环
  11. # for()循环除了创建方式以外,其余的都和while一样,
  12. # 包括else、包括break continue都可以在for循环中使用
  13. # 并且for循环使用也更加简单
  14. for i in range(30):
  15. print(i)
  16. #也可以遍历字符串
  17. for s in 'hello':
  18. print(s)

列表的遍历

遍历列表,指的就是将列表中的所有元素取出来

遍历列表(通过索引遍历)

  1. # 创建列表
  2. stus = ['孙悟空','猪八戒','沙和尚','唐僧','白骨精','蜘蛛精']
  3. # 遍历列表(通过索引遍历)
  4. # print(stus[0])
  5. # print(stus[1])
  6. # print(stus[2])
  7. # print(stus[3])

通过while循环来遍历列表

  1. # 通过while循环来遍历列表
  2. # i = 0
  3. # while i < len(stus):
  4. # print(stus[i])
  5. # i += 1

通过for循环来遍历列表

  1. # 通过for循环来遍历列表
  2. # 语法:
  3. # for 变量 in 序列 :
  4. # 代码块
  5. # for循环的代码块会执行多次,序列中有几个元素就会执行几次
  6. # 没执行一次就会将序列中的一个元素赋值给变量,
  7. # 所以我们可以通过变量,来获取列表中的元素
  8. for s in stus :
  9. print(s)

EMS 练习

Employee Manager System 员工管理系统
代码需求:

  1. - 做命令行版本的员工管理系统
  2. - 功能:
  3. 四个:
  4. 1.查询
  5. - 显示当前系统当中的所有员工
  6. 2.添加
  7. - 将员工添加到当前系统中
  8. 3.删除
  9. - 将员工从系统当中删除
  10. 4.退出
  11. - 退出系统
  12. - 员工信息要保存到哪里? 列表,在系统中应该有一个列表,专门用来保存所有员工信息的

代码实现:

  1. # 显示系统的欢迎信息
  2. print('-'*20 , '欢迎使用员工管理系统', '-'*20)
  3. # 创建一个列表,用来保存员工的信息,员工的信息以字符串的形式统一保存到列表
  4. emps = ['孙悟空\t18\t男\t花果山','猪八戒\t28\t男\t高老庄']
  5. # 创建一个死循环
  6. while True:
  7. # 显示用户的选项
  8. print('请选择要做的操作:')
  9. print('\t1.查询员工')
  10. print('\t2.添加员工')
  11. print('\t3.删除员工')
  12. print('\t4.退出系统')
  13. user_choose = input('请选择[1-4]:')
  14. print('-'*62)
  15. # 根据用户的选择做相关的操作
  16. if user_choose == '1' :
  17. # 查询员工
  18. # 打印表头
  19. print('\t序号\t姓名\t年龄\t性别\t住址')
  20. # 创建一个变量,来表示员工的序号
  21. n = 1
  22. # 显示员工信息
  23. for emp in emps :
  24. print(f'\t{n}\t{emp}')
  25. n += 1
  26. elif user_choose == '2':
  27. # 添加员工
  28. # 获取要添加员工的信息,姓名、年龄、性别、住址
  29. emp_name = input('请输入员工的姓名:')
  30. emp_age = input('请输入员工的年龄:')
  31. emp_gender = input('请输入员工的性别:')
  32. emp_address = input('请输入员工的住址:')
  33. # 创建员工信息
  34. # 将四个信息拼接为一个字符串,然后插入到列表中
  35. emp = f'{emp_name}\t{emp_age}\t{emp_gender}\t{emp_address}'
  36. # 显示一个提示信息
  37. print('以下员工将被添加到系统中')
  38. print('-'*62)
  39. print('姓名\t年龄\t性别\t住址')
  40. print(emp)
  41. print('-'*62)
  42. user_confirm = input('是否确认该操作[Y/N]:')
  43. # 判断
  44. if user_confirm == 'y' or user_confirm == 'yes' :
  45. # 确认
  46. emps.append(emp)
  47. # 显示提示信息
  48. print('添加成功!')
  49. else :
  50. # 取消操作
  51. print('添加已取消!')
  52. elif user_choose == '3':
  53. # 删除员工,根据员工的序号来删除员工
  54. # 获取要删除的员工的序号
  55. del_num = int(input('请输入要删除的员工的序号:'))
  56. # 判断序号是否有效
  57. if 0 < del_num <= len(emps) :
  58. # 输入合法,根据序号来获取索引
  59. del_i = del_num - 1
  60. # 显示一个提示信息
  61. print('以下员工将被删除')
  62. print('-'*62)
  63. print('\t序号\t姓名\t年龄\t性别\t住址')
  64. print(f'\t{del_num}\t{emps[del_i]}')
  65. print('-'*62)
  66. user_confirm = input('该操作不可恢复,是否确认[Y/N]:')
  67. # 判断
  68. if user_confirm == 'y' or user_confirm == 'yes' :
  69. # 删除元素
  70. emps.pop(del_i)
  71. # 显示提示
  72. print('员工已被删除!')
  73. else :
  74. # 操作取消
  75. print('操作已取消!')
  76. else :
  77. # 输入有误
  78. print('您的输入有误,请重新操作!')
  79. elif user_choose == '4':
  80. # 退出
  81. print('欢迎使用!再见!')
  82. input('点击回车键退出!')
  83. break
  84. else :
  85. print('您的输入有误,请重新选择!')
  86. # 打印分割线
  87. print('-'*62)

元组

元组 tuple(除了不可变,剩下的和序列差不多)
元组是一个不可变的序列,它的操作的方式基本上和列表是一致的,所以你在操作元组时,就把元组当成是一个不可变的列表就ok了
一般当我们希望数据不改变时,就使用元组,其余情况都使用列表.

创建元组:

  1. # 创建元组
  2. # 使用()来创建元组
  3. my_tuple = () # 创建了一个空元组
  4. # print(my_tuple,type(my_tuple)) # <class 'tuple'>
  5. my_tuple = (1,2,3,4,5) # 创建了一个5个元素的元组
  6. # 元组是不可变对象,不能尝试为元组中的元素重新赋值
  7. # my_tuple[3] = 10 TypeError: 'tuple' object does not support item assignment
  8. # print(my_tuple[3])
  9. # 当元组不是空元组时,括号可以省略
  10. # 如果元组不是空元组,它里边至少要有一个,(逗号)
  11. my_tuple = 10,20,30,40
  12. my_tuple = 40,
  13. # print(my_tuple , type(my_tuple))
  14. my_tuple = 10 , 20 , 30 , 40

元组的解包(解构)

  1. # 解包指就是将元组当中每一个元素都赋值给一个变量
  2. a,b,c,d = my_tuple
  3. # print("a =",a)
  4. # print("b =",b)
  5. # print("c =",c)
  6. # print("d =",d)
  7. a = 100
  8. b = 300
  9. # print(a , b)
  10. # 交互a 和 b的值,这时我们就可以利用元组的解包(把后面的部分看作一个元组)
  11. a , b = b , a
  12. # print(a , b)
  13. my_tuple = 10 , 20 , 30 , 40
  14. # 在对一个元组进行解包时,变量的数量必须和元组中的元素的数量一致
  15. # 也可以在变量前边添加一个*,这样变量将会获取元组中所有剩余的元素
  16. a , b , *c = my_tuple
  17. a , *b , c = my_tuple
  18. *a , b , c = my_tuple
  19. a , b , *c = [1,2,3,4,5,6,7]
  20. a , b , *c = 'hello world'
  21. # 不能同时出现两个或以上的*变量
  22. # *a , *b , c = my_tuple SyntaxError: two starred expressions in assignment
  23. print('a =',a)
  24. print('b =',b)
  25. print('c =',c)
  26. 上面三行的输出:
  27. a = h
  28. b = e
  29. c = ['l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']

可变对象

  1. - 每个对象中都保存了三个数据:
  2. id(标识)
  3. type(类型)
  4. value(值)
  5. - 列表就是一个可变对象
  6. a = [1,2,3]
  7. - a[0] = 10 (改对象)(像指针一样)
  8. - 这个操作是在通过变量去修改对象的值
  9. - 这种操作不会改变变量所指向的对象
  10. - 当我们去修改对象时,如果有其他变量也指向了该对象,则修改也会在其他的变量中体现
  11. - a = [4,5,6] (改变量)
  12. - 这个操作是在给变量重新赋值
  13. - 这种操作会改变变量所指向的对象
  14. - 为一个变量重新赋值时,不会影响其他的变量
  15. - 一般只有在为变量赋值时才是修改变量,其余的都是修改对象

== != is is not的区别

== != 比较的是对象的值是否相等
is is not 比较的是对象的id是否相等(比较两个对象是否是同一个对象)

  1. a = [1,2,3]
  2. b = [1,2,3]
  3. print(a,b)
  4. print(id(a),id(b))
  5. print(a == b) # a和b的值相等,使用==会返回True
  6. print(a is b) # a和b不是同一个对象,内存地址不同,使用is会返回False

字典(dict)

字典属于一种新的数据结构,称为映射(mapping)
字典的作用和列表类似,都是用来存储对象的容器。列表存储数据的性能很好,但是查询数据的性能的很差。在字典中每一个元素都有一个唯一的名字,通过这个唯一的名字可以快速的查找到指定的元素。

在查询元素时,字典的效率是非常快的
在字典中可以保存多个对象,每个对象都会有一个唯一的名字

  1. 1. 这个唯一的名字,我们称其为键(key),通过key可以快速的查询value
  2. 2. 这个对象,我们称其为值(value
  3. 3. 所以字典,我们也称为叫做键值对(key-value)结构
  4. 4. 每个字典中都可以有多个键值对,而每一个键值对我们称其为一项(item
  1. # 使用 {} 来创建字典
  2. d = {} # 创建了一个空字典
  3. # 创建一个包含有数据的字典
  4. # 语法:
  5. # {key:value,key:value,key:value}
  6. # 字典的值可以是任意对象
  7. # 字典的键可以是任意的不可变对象(int、str、bool、tuple ...),但是一般我们都会使用str
  8. # 字典的键是不能重复的,如果出现重复的后边的会替换到前边的
  9. # d = {'name':'孙悟空' , 'age':18 , 'gender':'男' , 'name':'sunwukong'}
  10. d = {
  11. 'name':'孙悟空' ,
  12. 'age':18 ,
  13. 'gender':'男' ,
  14. 'name':'sunwukong'
  15. }
  16. # print(d , type(d))
  17. # 需要根据键来获取值
  18. print(d['name'],d['age'],d['gender'])
  19. # 如果使用了字典中不存在的键,会报错
  20. # print(d['hello']) KeyError: 'hello'

字典的使用

创建字典:
  1. # 创建字典
  2. # 使用{}
  3. # 语法:{k1:v1,k2:v2,k3:v3}
  4. # 使用 dict()函数来创建字典
  5. # 每一个参数都是一个键值对,参数名就是键,参数名就是值(这种方式创建的字典,key都是字符串)
  6. d = dict(name='孙悟空',age=18,gender='男')
  7. # 也可以将一个包含有双值子序列的序列转换为字典
  8. # 双值序列,序列中只有两个值,[1,2] ('a',3) 'ab'
  9. # 子序列,如果序列中的元素也是序列,那么我们就称这个元素为子序列
  10. # [(1,2),(3,5)]
  11. d = dict([('name','孙悟空'),('age',18)])
  12. # print(d , type(d))
  13. d = dict(name='孙悟空',age=18,gender='男')

获取字典中键值对的个数
  1. # len() 获取字典中键值对的个数
  2. print(len(d))

检查字典中是否包含指定的键
  1. # in 检查字典中是否包含指定的键
  2. # not in 检查字典中是否不包含指定的键
  3. print('hello' in d)

获取字典中的值
  1. # 第一种,根据键来获取值
  2. # 语法:d[key]
  3. print(d['age'])#要加引号
  4. n = 'name' #要加引号
  5. print(d[n])
  6. # 第二种,通过[]来获取值时,如果键不存在,会抛出异常 KeyError
  7. # get(key[, default]) 该方法用来根据键来获取字典中的值
  8. # 如果获取的键在字典中不存在,会返回None
  9. # 也可以指定一个默认值,来作为第二个参数,这样获取不到值时将会返回默认值
  10. print(d.get('name'))
  11. print(d.get('hello','默认值'))

修改字典 添加键值对
  1. # 修改字典
  2. # d[key] = value 如果key存在则覆盖,不存在则添加
  3. d['name'] = 'sunwukong' # 修改字典的key-value
  4. d['address'] = '花果山' # 向字典中添加key-value
  5. # setdefault(key[, default]) 方法可以用来向字典中添加key-value
  6. # 如果key已经存在于字典中,则返回key的值,不会对字典做任何操作
  7. # 如果key不存在,则向字典中添加这个key,并设置value
  8. result = d.setdefault('name','猪八戒')
  9. result = d.setdefault('hello','猪八戒')
  10. # update([other])
  11. # 将其他的字典中的key-value添加到当前字典中
  12. # 如果有重复的key,则后边的会替换到当前的
  13. d = {'a':1,'b':2,'c':3}
  14. d2 = {'d':4,'e':5,'f':6, 'a':7}
  15. d.update(d2)

修改字典 删除键值对
  1. # 删除,可以使用 del 来删除字典中的 key-value
  2. d = {'a':1,'b':2,'c':3}
  3. del d['a']
  4. del d['b']
  5. # popitem()方法
  6. # 随机删除字典中的一个键值对,一般都会删除最后一个键值对
  7. # 删除之后,它会将删除的key-value作为返回值返回
  8. # 返回的是一个元组,元组中有两个元素,第一个元素是删除的key,第二个是删除的value
  9. # 当使用popitem()删除一个空字典时,会抛出异常 KeyError: 'popitem(): dictionary is empty'
  10. d.popitem()
  11. result = d.popitem()
  12. # pop(key[, default])方法
  13. # 根据key删除字典中的key-value
  14. # 会将被删除的value返回!
  15. # 如果删除不存在的key,会抛出异常
  16. # 如果指定了默认值,再删除不存在的key时,不会报错,而是直接返回默认值
  17. result = d.pop('d')
  18. result = d.pop('z','这是默认值')
  19. # clear()用来清空字典
  20. d.clear()

修改字典 浅复制
  1. copy()
  2. # 该方法用于对字典进行浅复制
  3. # 复制以后的对象,和原对象是独立,修改一个不会影响另一个
  4. # 注意,浅复制会简单复制对象内部的值,如果值也是一个可变对象,这个可变对象不会被复制
  5. d = {'a':1,'b':2,'c':3}
  6. d2 = d.copy()
  7. # d['a'] = 100

例子:(没太理解——2022.4.11)

  1. 例子:
  2. d = {'a':{'name':'孙悟空','age':18},'b':2,'c':3}
  3. d2 = d.copy()
  4. d2['a']['name'] = '猪八戒'
  5. print('d = ',d , id(d))
  6. print('d2 = ',d2 , id(d2))
  7. 运行结果:
  8. d = {'a': {'name': '猪八戒', 'age': 18}, 'b': 2, 'c': 3} 2080115470648
  9. d2 = {'a': {'name': '猪八戒', 'age': 18}, 'b': 2, 'c': 3} 2080115471128

修改字典 遍历字典
  1. # 遍历字典(三个方法)
  2. # keys() 该方法会返回字典的所有的key
  3. # 该方法会返回一个序列,序列中保存有字典的所有的键
  4. d = {'name':'孙悟空','age':18,'gender':'男'}
  5. # 通过遍历keys()来获取所有的键
  6. for k in d.keys() :
  7. print(k , d[k])
  8. # values()
  9. # 该方法会返回一个序列,序列中保存有字典的左右的值
  10. for v in d.values():
  11. print(v)
  12. # items()
  13. # 该方法会返回字典中所有的项
  14. # 它会返回一个序列,序列中包含有双值子序列
  15. # 双值分别是,字典中的key和value 然后进行元组的解包
  16. print(d.items())
  17. for k,v in d.items() :
  18. print(k , '=' , v)

集合(set)

集合和列表非常相似

不同点:

  1. 集合中只能存储不可变对象
  2. 合中存储的对象是无序(不是按照元素的插入顺序保存)不能通过索引操作集合
  3. 集合中不能出现重复的元素

创建集合

  1. # 使用 {} 来创建集合
  2. s = {10,3,5,1,2,1,2,3,1,1,1,1} # <class 'set'>
  3. # s = {[1,2,3],[4,6,7]} TypeError: unhashable type: 'list'
  4. #不能储存可变对象
  5. # 使用 set() 函数来创建集合
  6. s = set() # 空集合
  7. # 可以通过set()来将序列和字典转换为集合
  8. s = set([1,2,3,4,5,1,1,2,3,4,5])
  9. s = set('hello')
  10. s = set({'a':1,'b':2,'c':3}) # 使用set()将字典转换为集合时,只会包含字典中的键

集合的操作

  1. # 创建集合
  2. s = {'a' , 'b' , 1 , 2 , 3 , 1}
  3. # 使用in和not in来检查集合中的元素
  4. # print('c' in s)
  5. # 使用len()来获取集合中元素的数量
  6. # print(len(s))
  7. # add() 向集合中添加元素
  8. s.add(10)
  9. s.add(30)
  10. # update() 将一个集合中的元素添加到当前集合中
  11. # update()可以传递序列或字典作为参数,字典只会使用键
  12. s2 = set('hello')
  13. s.update(s2)
  14. s.update((10,20,30,40,50))
  15. s.update({10:'ab',20:'bc',100:'cd',1000:'ef'})
  16. # {1, 2, 3, 100, 40, 'o', 10, 1000, 'a', 'h', 'b', 'l', 20, 50, 'e', 30}
  17. # pop()随机删除并返回一个集合中的元素
  18. # result = s.pop()
  19. # remove()删除集合中的指定元素
  20. s.remove(100)
  21. s.remove(1000)
  22. # clear()清空集合
  23. s.clear()
  24. # copy()对集合进行浅复制
  25. s2 = s.copy()

集合的运算

  1. # 在对集合做运算时,不会影响原来的集合,而是返回一个运算结果
  2. # 创建两个集合
  3. s = {1,2,3,4,5}
  4. s2 = {3,4,5,6,7}
  5. # & 交集运算
  6. result = s & s2 # {3, 4, 5}
  7. # | 并集运算
  8. result = s | s2 # {1,2,3,4,5,6,7}
  9. # - 差集
  10. result = s - s2 # {1, 2}
  11. # ^ 异或集 获取只在一个集合中出现的元素
  12. result = s ^ s2 # {1, 2, 6, 7}
  13. # <= 检查一个集合是否是另一个集合的子集
  14. # 如果a集合中的元素全部都在b集合中出现,那么a集合就是b集合的子集,b集合是a集合超集
  15. a = {1,2,3}
  16. b = {1,2,3,4,5}
  17. result = a <= b # True
  18. result = {1,2,3} <= {1,2,3} # True
  19. result = {1,2,3,4,5} <= {1,2,3} # False
  20. # < 检查一个集合是否是另一个集合的真子集
  21. # 如果超集b中含有子集a中所有元素,并且b中还有a中没有的元素,则b就是a的真超集,a是b的真子集
  22. result = {1,2,3} < {1,2,3} # False
  23. result = {1,2,3} < {1,2,3,4,5} # True
  24. # >= 检查一个集合是否是另一个的超集
  25. # > 检查一个集合是否是另一个的真超集
  26. print('result =',result)

第五部分 函数

函数简介(function)

  1. - 函数也是一个对象
  2. - 对象是内存中专门用来存储数据的一块区域
  3. - 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用
  4. - 创建函数:
  5. def 函数名([形参1,形参2,...形参n]) :
  6. 代码块
  7. - 函数名必须要符号标识符的规范
  8. (可以包含字母、数字、下划线、但是不能以数字开头)
  9. - 函数中保存的代码不会立即执行,需要调用函数代码才会执行
  10. - 调用函数:
  11. 函数对象()
  12. - 定义函数一般都是要实现某种功能的

定义函数

  1. # 比如有如下三行代码,这三行代码是一个完整的功能
  2. # print('Hello')
  3. # print('你好')
  4. # print('再见')
  5. # 定义一个函数
  6. def fn() :
  7. print('这是我的第一个函数!')
  8. print('hello')
  9. print('今天天气真不错!')
  10. # 打印fn
  11. # print(fn) <function fn at 0x03D2B618>
  12. # print(type(fn)) <class 'function'>
  13. # fn是函数对象 fn()调用函数
  14. # print是函数对象 print()调用函数
  15. # fn()
  16. # 调用fn函数
  17. # 定义一个函数,可以用来求任意两个数的和
  18. def sum() :
  19. a = 123
  20. b = 456
  21. print(a + b)
  22. # 定义函数时指定形参
  23. def fn2(a , b) :
  24. # print('a =',a)
  25. # print('b =',b)
  26. print(a,"+",b,"=",a + b)
  27. # 调用函数时,来传递实参
  28. fn2(10,20)
  29. fn2(123,456)

函数的参数

  1. - 在定义函数时,可以在函数名后的()中定义数量不等的形参,
  2. 多个形参之间使用,隔开
  3. - 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值
  4. - 实参(实际参数)
  5. - 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参,
  6. 实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参

练习1:定义一个函数,可以用来求任意三个数的乘积
  1. # 求任意三个数的乘积
  2. def mul(a,b,c):
  3. print(a*b*c)

练习1:定义一个函数,可以根据不同的用户名显示不同的欢迎信息
  1. # 根据不同的用户名显示不同的欢迎信息
  2. def welcome(username):
  3. print('欢迎',username,'光临')
  4. # mul(1,2,3)
  5. # welcome('孙悟空')

参数传递实例:
  1. # 定义一个函数
  2. # 定义形参时,可以为形参指定默认值
  3. # 指定了默认值以后,如果用户传递了参数则默认值没有任何作用
  4. # 如果用户没有传递,则默认值就会生效
  5. def fn(a = 5 , b = 10 , c = 20):
  6. print('a =',a)
  7. print('b =',b)
  8. print('c =',c)
  9. # fn(1 , 2 , 3)
  10. # fn(1 , 2)
  11. # fn()
  12. # 实参的传递方式
  13. # 位置参数
  14. # 位置参数就是将对应位置的实参复制给对应位置的形参
  15. # 第一个实参赋值给第一个形参,第二个实参赋值给第二个形参 。。。
  16. # fn(1 , 2 , 3)
  17. # 关键字参数
  18. # 关键字参数,可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数
  19. # fn(b=1 , c=2 , a=3)
  20. # print('hello' , end='')
  21. # 位置参数和关键字参数可以混合使用
  22. # 混合使用关键字和位置参数时,必须将位置参数写到前面
  23. # fn(1,c=30)
  24. def fn2(a):
  25. print('a =',a)
  26. # 函数在调用时,解析器不会检查实参的类型
  27. # 实参可以传递任意类型的对象(和C有所区别)
  28. b = 123
  29. b = True
  30. b = 'hello'
  31. b = None
  32. b = [1,2,3]
  33. # fn2(b)
  34. fn2(fn)
  35. # 参数类型任意方便,但也会产生一些问题
  36. def fn3(a , b):
  37. print(a+b)
  38. # fn3(123,"456")
  39. def fn4(a):
  40. # 在函数中对形参进行重新赋值,不会影响其他的变量
  41. # a = 20
  42. # a是一个列表,尝试修改列表中的元素
  43. # 如果形参执行的是一个对象,当我们通过形参去修改对象时(该对象)
  44. # 会影响到所有指向该对象的变量(类似于传地址调用)
  45. a[0] = 30
  46. print('a =',a,id(a))
  47. c = 10
  48. c = [1,2,3]
  49. fn4(c)
  50. # 想要传值调用,不改变实参本身,可以这样
  51. # fn4(c.copy())
  52. # fn4(c[:])

不定长的参数:
  1. # 不定长的参数
  2. # 定义一个函数,可以求任意个数字的和
  3. # 在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参
  4. def sum(*nums):
  5. # 定义一个变量,来保存结果
  6. result = 0
  7. # 遍历元组,并将元组中的数进行累加
  8. for n in nums :
  9. result += n
  10. print(result)
  11. # sum(123,456,789,10,20,30,40) 想要参数数量随便变化
  12. # 在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参
  13. # 它将会将所有的实参保存到一个元组中
  14. # a,b,*c = (1,2,3,4,5,6)
  15. # *a会接受所有的位置实参,并且会将这些实参统一保存到一个元组中(装包)
  16. def fn(*a):
  17. print("a =",a,type(a))
  18. # fn(1,2,3,4,5)
  19. # 带星号的形参只能有一个
  20. # 带星号的参数,可以和其他参数配合使用
  21. # 第一个参数给a,第二个参数给b,剩下的都保存到c的元组中
  22. # def fn2(a,b,*c):
  23. # print('a =',a)
  24. # print('b =',b)
  25. # print('c =',c)
  26. # 可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递(c就必须使用关键字参数的形式传递)
  27. # 第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数
  28. # def fn2(a,*b,c):
  29. # print('a =',a)
  30. # print('b =',b)
  31. # print('c =',c)
  32. # 所有的位置参数都给a,b和c必须使用关键字参数
  33. # def fn2(*a,b,c):
  34. # print('a =',a)
  35. # print('b =',b)
  36. # print('c =',c)
  37. # 如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递
  38. def fn2(*,a,b,c):
  39. print('a =',a)
  40. print('b =',b)
  41. print('c =',c)
  42. # fn2(a=3,b=4,c=5)
  43. # *形参只能接收位置参数,而不能接收关键字参数
  44. # def fn3(*a) :
  45. # print('a =',a)
  46. # **形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中
  47. # 字典的key就是参数的名字,字典的value就是参数的值
  48. # **形参只能有一个,并且必须写在所有参数的最后
  49. def fn3(b,c,**a) :
  50. print('a =',a,type(a))
  51. print('b =',b)
  52. print('c =',c)
  53. # fn3(b=1,d=2,c=3,e=10,f=20)
  54. # 参数的解包(拆包)
  55. def fn4(a,b,c):
  56. print('a =',a)
  57. print('b =',b)
  58. print('c =',c)
  59. # 创建一个元组
  60. t = (10,20,30)
  61. # 传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递
  62. # 这里要求序列中元素的个数必须和形参的个数的一致
  63. # fn4(*t)
  64. # 创建一个字典
  65. d = {'a':100,'b':200,'c':300}
  66. # 通过 **来对一个字典进行解包操作
  67. fn4(**d)

函数的返回值:

返回值,返回值就是函数执行以后返回的结果
可以通过 return 来指定函数的返回值
可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值

这是一个没有返回值的函数:

  1. def sum(*nums):
  2. # 定义一个变量,来保存结果
  3. result = 0
  4. # 遍历元组,并将元组中的数进行累加
  5. for n in nums :
  6. result += n
  7. print(result)
  8. # sum(123,456,789)

return 后边跟什么值,函数就会返回什么值
return 后边可以跟任意的对象(字符串,列表,字典),返回值甚至可以是一个函数

这是一个有返回值的函数:

  1. def fn():
  2. # return 'Hello'
  3. # return [1,2,3]
  4. # return {'k':'v'}
  5. def fn2() :
  6. print('hello')#嵌套函数
  7. return fn2 # 返回值也可以是一个函数
  8. r = fn() # 这个函数的执行结果就是它的返回值

如果仅仅写一个return 或者 不写return,则相当于return None
在函数中,return后的代码都不会执行,return 一旦执行函数自动结束

return continue break三者的区别:

  1. def fn4() :
  2. for i in range(5):
  3. if i == 3 :
  4. # break 用来退出当前循环
  5. # continue 用来跳过当次循环
  6. return # return 用来结束函数
  7. print(i)
  8. print('循环执行完毕!')

fn5 和 fn5()的区别

  1. def fn5():
  2. return 10
  3. print(fn5)
  4. # fn5是函数对象,打印fn5实际是在打印函数对象 <function fn5 at 0x05771BB8>
  5. print(fn5())
  6. # fn5()是在调用函数,打印fn5()实际上是在打印fn5()函数的返回值 10

文档字符串(函数的描述)

help 函数

help()是Python中的内置函数
通过help()函数可以查询python中的函数的用法
语法:help(函数对象)

  1. help(print) # 获取print()函数的使用说明
  2. 结果:
  3. Help on built-in function print in module builtins:
  4. print(...)
  5. print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
  6. Prints the values to a stream, or to sys.stdout by default.
  7. Optional keyword arguments:
  8. file: a file-like object (stream); defaults to the current sys.stdout.
  9. sep: string inserted between values, default a space.
  10. end: string appended after the last value, default a newline.
  11. flush: whether to forcibly flush the stream.

利用函数字符串编写函数说明
  1. # 文档字符串(doc str)
  2. # 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明
  3. # 当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明
  4. # 文档字符串非常简单,其实直接在函数的第一行写一个字符串就是文档字符串
  5. def fn(a:int,b:bool,c:str='hello') -> int:#这里等于号后面是对参数类型的描述,后面的箭头表示其返回值的类型
  6. '''
  7. 这是一个文档字符串的示例(尽量使用英文编写)
  8. 函数的作用:。。。。。
  9. 函数的参数:
  10. a,作用,类型,默认值。。。。
  11. b,作用,类型,默认值。。。。
  12. c,作用,类型,默认值。。。。
  13. '''
  14. return 10
  15. help(fn)

函数的作用域和命名空间

作用域

作用域(scope)
作用域指的是变量生效的区域

  1. b = 20 # 全局变量
  2. def fn():
  3. a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问
  4. print('函数内部:','a =',a)
  5. print('函数内部:','b =',b)
  6. fn()
  7. print('函数外部:','a =',a)#无法调用
  8. print('函数外部:','b =',b)

在Python中一共有两种作用域
全局作用域

  • 全局作用域在程序执行时创建,在程序执行结束时销毁
  • 所有函数以外的区域都是全局作用域
  • 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问

函数作用域

  • 函数作用域在函数调用时创建,在调用结束时销毁
  • 函数每调用一次就会产生一个新的函数作用域
  • 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问

变量的查找

当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,如果没有则继续去上一级作用域中寻找,如果有则使用,
如果依然没有则继续去上一级作用域中寻找,以此类推。直到找到全局作用域,依然没有找到,则会抛出异常:
NameError: name ‘a’ is not defined

变量修改:

  1. a = 20
  2. def fn3():
  3. # a = 10 # 在函数中为变量赋值时,默认都是为局部变量赋值
  4. # 如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量
  5. global a # 声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a
  6. a = 10 # 修改全局变量
  7. print('函数内部:','a =',a)

命名空间

命名空间(namespace)
命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
每一个作用域都会有一个它对应的命名空间
全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
命名空间实际上就是一个字典,是一个专门用来存储变量的字典

locals()用来获取当前作用域的命名空间
如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
返回的是一个字典

  1. scope = locals() # 当前命名空间
  2. print(type(scope))
  3. # print(a)
  4. # print(scope['a'])
  5. # 向scope中添加一个key-value
  6. scope['c'] = 1000 # 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做)
  7. # print(c)
  1. def fn4():
  2. a = 10
  3. # scope = locals() # 在函数内部调用locals()会获取到函数的命名空间
  4. # scope['b'] = 20 # 可以通过scope来操作函数的命名空间,但是也是不建议这么做
  5. # globals() 函数可以用来在任意位置获取全局命名空间
  6. global_scope = globals()
  7. # print(global_scope['a'])
  8. global_scope['a'] = 30
  9. # print(scope)
  10. fn4()

递归

求10的阶乘

基础:

  1. # 尝试求10的阶乘(10!)
  2. # 1! = 1
  3. # 2! = 1*2 = 2
  4. # 3! = 1*2*3 = 6
  5. # 4! = 1*2*3*4 = 24
  6. # print(1*2*3*4*5*6*7*8*9*10)

函数:

  1. # 创建一个变量保存结果
  2. # n = 10
  3. # for i in range(1,10):
  4. # n *= i
  5. # print(n)
  6. # 创建一个函数,可以用来求任意数的阶乘
  7. def factorial(n):
  8. '''
  9. 该函数用来求任意数的阶乘
  10. 参数:
  11. n 要求阶乘的数字
  12. '''
  13. # 创建一个变量,来保存结果
  14. result = n
  15. for i in range(1,n):
  16. result *= i
  17. return result
  18. # 求10的阶乘
  19. # print(factorial(20))

递归式的函数:
从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢?
从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢?….
递归简单理解就是自己去引用自己!
递归式函数,在函数中自己调用自己!

  1. # 无穷递归,如果这个函数被调用,程序的内存会溢出,效果类似于死循环
  2. def fn():
  3. fn()
  4. fn()

递归是解决问题的一种方式,它和循环很像

它的整体思想是,将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题
递归式函数的两个要件
1.基线条件

  • 问题可以被分解为的最小问题,当满足基线条件时,递归就不在执行了

2.递归条件

  • 将问题继续分解的条件

递归和循环类似,基本是可以互相代替的,循环编写起来比较容易,阅读起来稍难,递归编写起来难,但是方便阅读

利用递归求阶乘:

  1. def factorial(n):
  2. '''
  3. 该函数用来求任意数的阶乘
  4. 参数:
  5. n 要求阶乘的数字
  6. '''
  7. # 基线条件 判断n是否为1,如果为1则此时不能再继续递归
  8. if n == 1 :
  9. # 1的阶乘就是1,直接返回1
  10. return 1
  11. # 递归条件
  12. return n * factorial(n-1)
  13. # print(factorial(10))

递归练习

创建一个函数 power 来为任意数字做幂运算 n ** i
  1. def power(n , i):
  2. '''
  3. power()用来为任意的数字做幂运算
  4. 参数:
  5. n 要做幂运算的数字
  6. i 做幂运算的次数
  7. '''
  8. # 基线条件
  9. if i == 1:
  10. # 求1次幂
  11. return n
  12. # 递归条件
  13. return n * power(n , i-1)
  14. # print(power(8,6))

创建一个函数,用来检查一个任意的字符串是否是回文字符串

先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串
如果一致,则看剩余的部分是否是回文字符串

  1. # abcdefgfedcba
  2. # 先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串
  3. # 如果一致,则看剩余的部分是否是回文字符串
  4. # 检查 abcdefgfedcba 是不是回文
  5. # 检查 bcdefgfedcb 是不是回文
  6. # 检查 cdefgfedc 是不是回文
  7. # 检查 defgfed 是不是回文
  8. # 检查 efgfe 是不是回文
  9. # 检查 fgf 是不是回文
  10. # 检查 g 是不是回文(基线条件)
  11. def hui_wen(s):
  12. '''
  13. 该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False
  14. 参数:
  15. s:就是要检查的字符串
  16. '''
  17. # 基线条件
  18. if len(s) < 2 :
  19. # 字符串的长度小于2,则字符串一定是回文
  20. return True
  21. elif s[0] != s[-1]:
  22. # 第一个字符和最后一个字符不相等,不是回文字符串
  23. return False
  24. # 递归条件
  25. return hui_wen(s[1:-1])
  26. print(hui_wen('abcdefgfedcba'))

高阶函数

函数式编程

在Python中,函数是一等对象

  • 一等对象一般都会具有如下特点:
    ① 对象是在运行时创建的
    ② 能赋值给变量或作为数据结构中的元素
    ③ 能作为参数传递
    ④ 能作为返回值返回

高阶函数

  • 高阶函数至少要符合以下两个特点中的一个
    ① 接收一个或多个函数作为参数
    ② 将函数作为返回值返回

一个普通的函数:

  1. # 创建一个列表
  2. l = [1,2,3,4,5,6,7,8,9,10]
  3. # 定义一个函数
  4. # 可以将指定列表中的所有的偶数,保存到一个新的列表中返回
  5. def fn(lst) :
  6. '''
  7. fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回
  8. 参数:
  9. lst:要进行筛选的列表
  10. '''
  11. # 创建一个新列表
  12. new_list = []
  13. # 对列表进行筛选
  14. for n in lst :
  15. # 判断n的奇偶
  16. if i % 2 == 0 ::
  17. new_list.append(n)
  18. # 返回新列表
  19. return new_list

函数化编程:

检查一个任意的数字是否是偶数

  1. # 定义一个函数,用来检查一个任意的数字是否是偶数
  2. def fn2(i) :
  3. if i % 2 == 0 :
  4. return True
  5. return False

这个函数用来检查指定的数字是否大于5

  1. # 这个函数用来检查指定的数字是否大于5
  2. def fn3(i):
  3. if i > 5 :
  4. return True
  5. return False

主函数:

  1. def fn(func , lst) :
  2. '''
  3. fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回
  4. 参数:
  5. lst:要进行筛选的列表
  6. '''
  7. # 创建一个新列表
  8. new_list = []
  9. # 对列表进行筛选
  10. for n in lst :
  11. # 判断n的奇偶
  12. if func(n) :
  13. new_list.append(n)
  14. # if n > 5 :
  15. # new_list.append(n)
  16. # 返回新列表
  17. return new_list

调用时,主函数可以直接选择调用任意函数,和参数 (规则和参数都作为输入)
当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数

  1. print(fn(fn2 , l))
  2. #实现的功能也是将指定列表中的所有的偶数,保存到一个新的列表中返回

filter()过滤器
  1. filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中
  2. 参数:
  3. 1.函数,根据该函数来过滤序列(可迭代的结构)
  4. 2.需要过滤的序列(可迭代的结构)
  5. 返回值:
  6. 过滤后的新序列(可迭代的结构)

示例:

  1. r=filter(fn4 ,l)#这里fn4作为参数,所以不加()
  2. print(list(r))
  3. # fn4是作为参数传递进filter()函数中
  4. # 而fn4实际上只有一个作用,就是作为filter()的参数
  5. # filter()调用完毕以后,fn4就已经没用

匿名函数:
  1. 匿名函数 lambda 函数表达式 (语法糖)
  2. lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式
  3. 语法:lambda 参数列表 : 返回值
  4. 匿名函数一般都是作为参数使用,其他地方一般不会使用

示例:

  1. #普通写法:
  2. def fn5(a , b):
  3. return a + b
  4. #匿名写法:
  5. lambda a,b : a + b
  6. 调用:整体加括号,参数也放进括号里
  7. (lambda a,b : a + b)(10,20)#一般不这么用
  8. # 也可以将匿名函数赋值给一个变量,一般不会这么做
  9. fn6 = lambda a,b : a + b
  10. # print(fn6(10,30))

对本节第一个程序的改造:

  1. def fn4(i):
  2. return i % 3 == 0
  3. #fn4可以有如上的简写
  4. #在利用filter()和匿名函数调用就是下面这样:
  5. r = filter(lambda i : i > 5 , l)
  6. print(list(r))
  7. #这两行就起到了本节第一个普通函数fn的效果

map()函数
  1. # map()
  2. # map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回
  3. l = [1,2,3,4,5,6,7,8,9,10]
  4. r = map(lambda i : i ** 2 , l)#求列表每一个元素的2次方
  5. # print(list(r))

sort()方法
  1. # sort()
  2. # 该方法用来对列表中的元素进行排序
  3. # sort()方法默认是直接比较列表中的元素的大小
  4. # 在sort()可以接收一个关键字参数 , key
  5. # key需要一个函数作为参数,当设置了函数作为参数
  6. # 每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小
  7. l = ['bb','aaaa','c','ddddddddd','fff']
  8. # l.sort(key=len)
  9. l = [2,5,'1',3,'6','4']
  10. l.sort(key=int)
  11. # print(l)

sorted()函数
  1. # sorted()
  2. # 这个函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序
  3. # 并且使用sorted()排序不会影响原来的对象,而是返回一个新对象
  4. l = [2,5,'1',3,'6','4']
  5. # l = "123765816742634781"
  6. print('排序前:',l)
  7. print(sorted(l,key=int))
  8. print('排序后:',l)

闭包

将函数作为返回值返回,也是一种高阶函数
这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量
可以将一些私有的数据藏到的闭包中

语法示例:

  1. def fn():
  2. a = 10
  3. # 函数内部再定义一个函数
  4. def inner():
  5. print('我是fn2' , a)
  6. # 将内部函数 inner作为返回值返回
  7. return inner
  8. # r是一个函数,是调用fn()后返回的函数
  9. # 这个函数实在fn()内部定义,并不是全局函数
  10. # 所以这个函数总是能访问到fn()函数内的变量,其他函数访问不了
  11. r = fn()
  12. r()

示例:求多个数的平均值:

正常写法:

  1. # 求多个数的平均值
  2. nums = [50,30,20,10,77]
  3. # sum()用来求一个列表中所有元素的和
  4. print(sum(nums)/len(nums))

闭包:

  1. # 形成闭包的要件
  2. # ① 函数嵌套
  3. # ② 将内部函数作为返回值返回
  4. # ③ 内部函数必须要使用到外部函数的变量
  5. def make_averager():
  6. # 创建一个列表,用来保存数值
  7. nums = []
  8. # 创建一个函数,用来计算平均值
  9. def averager(n) :
  10. # 将n添加到列表中
  11. nums.append(n)
  12. # 求平均值
  13. return sum(nums)/len(nums)
  14. return averager
  15. averager = make_averager()
  16. print(averager(10))
  17. print(averager(20))
  18. print(averager(30))
  19. print(averager(40))

装饰器

现在有以下程序:

  1. def add(a , b):
  2. '''
  3. 求任意两个数的和
  4. '''
  5. r = a + b
  6. return r
  7. def mul(a , b):
  8. '''
  9. 求任意两个数的积
  10. '''
  11. r = a * b
  12. return r
  13. r = add(123,456)
  14. print(r)

当前需求:希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕

我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
① 如果要修改的函数过多,修改起来会比较麻烦
② 并且不方便后期的维护
③ 并且这样做会违反开闭原则(OCP)

程序的设计,要求开发对程序的扩展,要关闭对程序的修改
我们希望在不修改原函数的情况下,来对函数进行扩展:

只需要根据现有的函数,来创建一个新的函数:

  1. def fn2():
  2. print('函数开始执行~~~')
  3. fn()
  4. print('函数执行结束~~~')

对add函数进行修改(记得传递参数)

  1. def new_add(a,b):
  2. print('计算开始~~~')
  3. r = add(a,b)
  4. print('计算结束~~~')
  5. return r
  6. # r = new_add(111,222)
  7. # print(r)

上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了
但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了
为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数

  1. def begin_end(old):
  2. '''
  3. 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束
  4. 参数:
  5. old 要扩展的函数对象
  6. '''
  7. # 创建一个新函数
  8. def new_function(*args , **kwargs):
  9. print('开始执行~~~~')
  10. # 调用被扩展的函数
  11. result = old(*args , **kwargs)
  12. print('执行结束~~~~')
  13. # 返回函数的执行结果
  14. return result
  15. # 返回新函数
  16. return new_function
  17. f = begin_end(fn)
  18. f2 = begin_end(add)
  19. f3 = begin_end(mul)
  20. # r = f()
  21. # r = f2(123,456)
  22. # r = f3(123,456)
  23. # print(r)

向begin_end()这种函数我们就称它为装饰器
通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
在开发中,我们都是通过装饰器来扩展函数的功能的
在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰

  1. @begin_end
  2. def say_hello():
  3. print('大家好~~~')
  4. say_hello()

这个就相当于:

  1. f = begin_end(say_hello)

第六部分 对象

什么是对象?

  1. - 对象是内存中专门用来存储数据的一块区域。
  2. - 对象中可以存放各种数据(比如:数字、布尔值、代码)
  3. - 对象由三部分组成:
  4. 1.对象的标识(id
  5. 2.对象的类型(type
  6. 3.对象的值(value

面向对象(oop)

  • Python是一门面向对象的编程语言
  • 所谓的面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的
    • 面向过程的编程的语言
      • 面向过程指将我们的程序的逻辑分解为一个一个的步骤,
        通过对每个步骤的抽象,来完成程序
        • 例子:
          • 孩子上学
            1.妈妈起床
            2.妈妈上厕所
            3.妈妈洗漱
            4.妈妈做早饭
            5.妈妈叫孩子起床
            6.孩子上厕所
            7.孩子要洗漱
            8.孩子吃饭
            9.孩子背着书包上学校
  • 面向过程的编程思想将一个功能分解为一个一个小的步骤,我们通过完成一个一个的小的步骤来完成一个程序
  • 这种编程方式,符合我们人类的思维,编写起来相对比较简单
  • 但是这种方式编写代码的往往只适用于一个功能,如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码,
    所以它可复用性比较低,并且难于维护
  1. - 面向对象的编程语言
  2. - 面向对象的编程语言,关注的是对象,而不关注过程
  3. - 对于面向对象的语言来说,一切都是对象
  4. - 例子:
  5. 1.孩他妈起床叫孩子上学
  6. - 面向对象的编程思想,将所有的功能统一保存到对应的对象中
  7. 比如,妈妈功能保存到妈妈的对象中,孩子的功能保存到孩子对象中
  8. 要使用某个功能,直接找到对应的对象即可
  9. - 这种方式编写的代码,比较容易阅读,并且比较易于维护,容易复用。
  10. - 但是这种方式编写,不太符合常规的思维,编写起来稍微麻烦一点

简单归纳一下,面向对象的思想

  1. 找对象
  2. 搞对象

类(class)

  • 我们目前所学习的对象都是Python内置的对象
  • 但是内置对象并不能满足所有的需求,所以我们在开发中经常需要自定义一些对象
  • 类,简单理解它就相当于一个图纸。在程序中我们需要根据类来创建对象
  • 类就是对象的图纸!
  • 我们也称对象是类的实例(instance)
  • 如果多个对象是通过一个类创建的,我们称这些对象是一类对象
  • 像 int() float() bool() str() list() dict() …. 这些都是类
  • a = int(10) # 创建一个int类的实例 等价于 a = 10
  • 我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名
  • 类也是一个对象!
  • 类就是一个用来创建对象的对象!
  • 类是type类型的对象,定义类实际上就是定义了一个type类型的对象

示例:定义一个简单的类

  1. # 定义一个简单的类
  2. # 使用class关键字来定义类,语法和函数很像!
  3. # class 类名([父类]):
  4. # 代码块
  5. class MyClass():
  6. pass
  7. print(MyClass) #得到: <class '__main__.MyClass'> 表示现在运行的是主文件的MyClass类

使用MyClass创建一个对象
使用类来创建对象,就像调用一个函数一样

  1. # 使用MyClass创建一个对象
  2. mc = MyClass() # mc就是通过MyClass创建的对象,mc是MyClass的实例
  3. mc_2 = MyClass()
  4. mc_3 = MyClass()
  5. mc_4 = MyClass()
  6. # mc mc_2 mc_3 mc_4 都是MyClass的实例,他们都是一类对象
  7. # isinstance()用来检查一个对象是否是一个类的实例
  8. result = isinstance(mc_2,MyClass) #true
  9. result = isinstance(mc_2,str) #false

现在我们通过MyClass这个类创建的对象都是一个空对象。也就是对象中实际上什么都没有,就相当于是一个空的盒子
可以向对象中添加变量,对象中的变量称为属性。

  1. 语法:对象.属性名 = 属性值
  2. mc.name = '孙悟空'
  3. mc_2.name = '猪八戒'
  4. print(mc_2.name)

使用类创建对象的流程(参考下图)

  1. 1.创建一个变量<br /> 2.在内存中创建一个新对象<br /> 3.将对象的id赋值给变量

Python笔记 - 图3

类的定义

  • 类和对象都是对现实生活中的事物或程序中的内容的抽象
  • 实际上所有的事物都由两部分构成:
    1.数据(属性)
    2.行为(方法)
  • 在类的代码块中,我们可以定义变量和函数,
    变量会成为该类实例的公共属性,所有的该类实例都可以通过 对象.属性名 的形式访问
    函数会成为该类实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式调用方法
  • 注意:
    方法调用时,第一个参数由解析器自动传递,所以定义方法时,至少要定义一个形参!
  • 实例为什么能访问到类中的属性和方法
    类中定义的属性和方法都是公共的,任何该类实例都可以访问
    • 属性和方法查找的流程
      当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性,
      如果有,则直接返回当前的对象的属性值,
      如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值,
      如果类对象中依然没有,则报错!
    • 类对象和实例对象中都可以保存属性(方法)
      - 如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中
      • 如果这个属性(方法)是某个实例独有,则应该保存到实例对象中
  • 一般情况下,属性保存到实例对象中,而方法需要保存到类对象中

尝试定义一个表示人的类:

Python笔记 - 图4

  1. # 尝试定义一个表示人的类
  2. class Person :
  3. # 在类的代码块中,我们可以定义变量和函数
  4. # 在类中我们所定义的变量,将会成为所有的实例的公共属性
  5. # 所有实例都可以访问这些变量
  6. name = 'swk' # 公共属性,所有实例都可以访问
  7. # 在类中也可以定义函数,类中的定义的函数,我们称为方法
  8. # 这些方法可以通过该类的所有实例来访问
  9. def say_hello(self) :
  10. # 方法每次被调用时,解析器都会自动传递第一个实参
  11. # 第一个参数,就是调用方法的对象本身,
  12. # 如果是p1调的,则第一个参数就是p1对象
  13. # 如果是p2调的,则第一个参数就是p2对象
  14. # 一般我们都会将这个参数命名为self
  15. # say_hello()这个方法,可以显示如下格式的数据:
  16. # 你好!我是 xxx
  17. # 在方法中不能直接访问类中的属性
  18. print('你好!我是 %s' %self.name)
  19. # 创建Person的实例
  20. p1 = Person()
  21. p2 = Person()
  22. # print(p2.name)
  23. # 调用方法,对象.方法名()
  24. # 方法调用和函数调用的区别
  25. # 如果是函数调用,则调用时传几个参数,就会有几个实参
  26. # 但是如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参
  27. # 修改p1的name属性
  28. p1.name = '猪八戒'
  29. p2.name = '沙和尚'
  30. p1.say_hello() # '你好!我是 猪八戒'
  31. p2.say_hello() # '你好!我是 沙和尚'
  32. # del p2.name # 删除p2的name属性
  33. # print(p1.name)
  34. # print(p2.name)

类对象的初始化

目前来讲,对于Person类来说name是必须的,并且每一个对象中的name属性基本上都是不同,
而我们现在是将name属性在定义为对象以后,手动添加到对象中,这种方式很容易出现错误

  1. # p1 = Person()
  2. # # 手动向对象添加name属性
  3. # p1.name = '孙悟空'
  4. # p2 = Person()
  5. # p2.name = '猪八戒'
  6. # p3 = Person()
  7. # p3.name = '沙和尚'

上面这样定义很麻烦

我们希望,在创建对象时,必须设置name属性,如果不设置对象将无法创建,并且属性的创建应该是自动完成的,而不是在创建对象以后手动完成。

在类中可以定义一些特殊方法(魔术方法)

  1. # 特殊方法都是以__开头,__结尾的方法
  2. # 特殊方法不需要我们自己调用,不要尝试去调用特殊方法
  3. # p1.__init__() 不要这么做
  4. # 特殊方法将会在特殊的时刻自动调用
  5. # 学习特殊方法:
  6. # 1.特殊方法什么时候调用
  7. # 2.特殊方法有什么作用
  8. # 创建对象的流程
  9. # p1 = Person()的运行流程
  10. # 1.创建一个变量
  11. # 2.在内存中创建一个新对象
  12. # 3.__init__(self)方法执行
  13. # 4.将对象的id赋值给变量
  14. # init会在对象创建以后立即执行
  15. # init可以用来向新创建的对象中初始化属性
  16. # 调用类创建对象时,类后边的所有参数都会依次传递到init()中
  1. #定义Person类
  2. class Person :
  3. def __init__(self,name):
  4. # print(self)
  5. # 通过self向新建的对象中初始化属性
  6. self.name = name
  7. def say_hello(self):
  8. print('大家好,我是%s'%self.name)
  9. #定义实例
  10. p1 = Person('孙悟空')
  11. p2 = Person('猪八戒')
  12. p3 = Person('沙和尚')
  13. p4 = Person('唐僧')
  14. #输出name
  15. print(p1.name)
  16. print(p2.name)
  17. print(p3.name)
  18. print(p4.name)

类的基本结构

  1. class 类名([父类]) :
  2. 公共的属性...
  3. # 对象的初始化方法
  4. def __init__(self,...):
  5. ...
  6. # 其他的方法
  7. def method_1(self,...):
  8. ...
  9. def method_2(self,...):
  10. ...
  11. ...

类的练习

定义一个表示dog的类
  1. 属性:nameagegenderheight
  2. ...
  3. 方法: jiao(),yao(),run()
  4. ...
  1. class Dog:
  2. '''
  3. 表示狗的类
  4. '''
  5. def __init__(self , name , age , gender , height):
  6. self.name = name
  7. self.age = age
  8. self.gender = gender
  9. self.height = height
  10. def jiao(self):
  11. '''
  12. 狗叫的方法
  13. '''
  14. print('汪汪汪~~~')
  15. def yao(self):
  16. '''
  17. 狗咬的方法
  18. '''
  19. print('我咬你~~')
  20. def run(self):
  21. print('%s 快乐的奔跑着~~'%self.name)
  22. d = Dog('小黑',8,'male',30)
  23. # 目前我们可以直接通过 对象.属性 的方式来修改属性的值,这种方式导致对象中的属性可以随意修改
  24. # 非常的不安全,值可以任意修改,不论对错
  25. # 现在我们就需要一种方式来增强数据的安全性
  26. # 1.属性不能随意修改(我让你改你才能改,不让你改你就不能改)
  27. # 2.属性不能修改为任意的值(年龄不能是负数)
  28. d.name = '阿黄' #这些不应该被随意更改
  29. d.age = -10 #这些不应该被随意更改
  30. d.run()
  31. print(d.age)
  32. # print(d.name , d.age , d.gender , d.height)

类的封装

  1. # 封装是面向对象的三大特性之一
  2. # 封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法
  3. # 如何隐藏一个对象中的属性?
  4. # - 将对象的属性名,修改为一个外部不知道的名字(最简单)
  5. class Dog:
  6. '''
  7. 表示狗的类
  8. '''
  9. def __init__(self , name , age):
  10. self.hidden_name = name
  11. self.hidden_age = age
  12. def say_hello(self):
  13. print('大家好,我是 %s'%self.hidden_name)
  14. # 如何获取(修改)对象中的属性?
  15. # - 需要提供一个getter和setter方法使外部可以访问到属性
  16. # - getter 获取对象中的指定属性(get_属性名)
  17. # - setter 用来设置对象的指定属性(set_属性名)
  18. def get_name(self):
  19. '''
  20. get_name()用来获取对象的name属性
  21. '''
  22. # print('用户读取了属性')
  23. return self.hidden_name
  24. def set_name(self , name):
  25. # print('用户修改了属性')
  26. self.hidden_name = name
  27. def get_age(self):
  28. return self.hidden_age
  29. def set_age(self , age):
  30. if age > 0 :
  31. self.hidden_age = age
  32. # 使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
  33. # 1.隐藏了属性名,使调用者无法随意的修改对象中的属性
  34. # 2.增加了getter和setter方法,很好的控制的属性是否是只读的
  35. # 如果希望属性是只读的,则可以直接去掉setter方法
  36. # 如果希望属性不能被外部访问,则可以直接去掉getter方法
  37. # 3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
  38. # 4.使用getter方法获取属性,使用setter方法设置属性
  39. # 可以在读取属性和修改属性的同时做一些其他的处理
  40. # 5.使用getter方法可以表示一些计算的属性

使用getter方法表示一些计算的属性:利用get计算矩形面积

  1. class Rectangle:
  2. '''
  3. 表示矩形的类
  4. '''
  5. def __init__(self,width,height):
  6. self.hidden_width = width
  7. self.hidden_height = height
  8. def get_width(self):
  9. return self.hidden_width
  10. def get_height(self):
  11. return self.hidden_height
  12. def set_width(self , width):
  13. self.hidden_width = width
  14. def set_height(self , height):
  15. self.hidden_height = height
  16. def get_area(self):
  17. return self.hidden_width * self.hidden_height
  18. # r = Rectangle(5,2)
  19. # r.set_width(10)
  20. # r.set_height(20)
  21. # print(r.get_area())

利用下划线进一步的隐藏属性:(用了根没用一样,和改属性名字原理相同,不过是python内置)

  1. # 可以为对象的属性使用双下划线开头,__xxx
  2. # 双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
  3. # 其实隐藏属性只不过是Python自动为属性改了一个名字
  4. # 实际上是将名字修改为了,_类名__属性名 比如 __name -> _Person__name
  5. class Person:
  6. def __init__(self,name):
  7. self.__name = name
  8. def get_name(self):
  9. return self.__name
  10. def set_name(self , name):
  11. self.__name = name
  12. p = Person('孙悟空')
  13. print(p.__name) #__开头的属性是隐藏属性,无法通过对象访问
  14. p.__name = '猪八戒' #同样也无法修改
  15. print(p._Person__name)
  16. p._Person__name = '猪八戒'
  17. # print(p.get_name())
  18. # 使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
  19. # 一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
  20. # 一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
  21. class Person:
  22. def __init__(self,name):
  23. self._name = name
  24. def get_name(self):
  25. return self._name
  26. def set_name(self , name):
  27. self._name = name
  28. p = Person('孙悟空')
  29. print(p._name)

property装饰器

简单理解就是把 p.set_name(“名字”) 装饰为 p.name = “名字” ,节省两个括号?

  1. class Person:
  2. def __init__(self,name,age):
  3. self._name = name
  4. self._age = age
  5. # property装饰器,用来将一个get方法,转换为对象的属性
  6. # 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
  7. # 使用property装饰的方法,必须和属性名是一样的
  8. @property
  9. def name(self):
  10. print('get方法执行了~~~')
  11. return self._name
  12. # setter方法的装饰器:@属性名.setter
  13. @name.setter
  14. def name(self , name):
  15. print('setter方法调用了')
  16. self._name = name
  17. @property
  18. def age(self):
  19. return self._age
  20. @age.setter
  21. def age(self , age):
  22. self._age = age
  23. p = Person('猪八戒',18)
  24. p.name = '孙悟空'
  25. p.age = 28
  26. print(p.name,p.age)

类的继承

继承
  1. # 定义一个类 Animal(动物)
  2. # 这个类中需要两个方法:run() sleep()
  3. class Animal:
  4. def run(self):
  5. print('动物会跑~~~')
  6. def sleep(self):
  7. print('动物睡觉~~~')
  8. # def bark(self):
  9. # print('动物嚎叫~~~')
  10. # 定义一个类 Dog(狗)
  11. # 这个类中需要三个方法:run() sleep() bark()
  12. class Dog:
  13. def run(self):
  14. print('狗会跑~~~')
  15. def sleep(self):
  16. print('狗睡觉~~~')
  17. def bark(self):
  18. print('汪汪汪~~~')
  19. # 有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能
  20. # 如何能让这个类来实现全部的功能呢?
  21. # ① 直接修改这个类,在这个类中添加我们需要的功能
  22. # - 修改起来会比较麻烦,并且会违反OCP原则
  23. # ② 直接创建一个新的类
  24. # - 创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,会出现大量的重复性代码
  25. # ③ 直接从Animal类中来继承它的属性和方法
  26. # - 继承是面向对象三大特性之一
  27. # - 通过继承我们可以使一个类获取到其他类中的属性和方法
  28. # - 在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super)
  29. # 子类(衍生类)可以直接继承父类中的所有的属性和方法
  30. #
  31. # 通过继承可以直接让子类获取到父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则
  32. # 所以我们经常需要通过继承来对一个类进行扩展
  33. class Dog(Animal):
  34. def bark(self):
  35. print('汪汪汪~~~')
  36. def run(self):
  37. print('狗跑~~~~')
  38. class Hashiqi(Dog):
  39. def fan_sha(self):
  40. print('我是一只傻傻的哈士奇')
  41. d = Dog()
  42. h = Hashiqi()
  43. # 在创建类时,如果省略了父类,则默认父类为object
  44. # object是所有类的父类,所有类都继承自object
  45. class Person(object):
  46. pass
  47. # issubclass() 检查一个类是否是另一个类的子类
  48. # print(issubclass(Animal , Dog))
  49. # print(issubclass(Animal , object))
  50. # print(issubclass(Person , object))
  51. # isinstance()用来检查一个对象是否是一个类的实例
  52. # 如果这个类是这个对象的父类,也会返回True
  53. # 所有的对象都是object的实例
  54. print(isinstance(print , object))

类方法的重写
  1. # 定义一个类 Animal(动物)
  2. # 这个类中需要两个方法:run() sleep()
  3. class Animal:
  4. def run(self):
  5. print('动物会跑~~~')
  6. def sleep(self):
  7. print('动物睡觉~~~')
  8. class Dog(Animal):
  9. def bark(self):
  10. print('汪汪汪~~~')
  11. def run(self):
  12. print('狗跑~~~~')
  13. # 如果在子类中如果有和父类同名的方法,则通过子类实例去调用方法时,
  14. # 会调用子类的方法而不是父类的方法,这个特点我们成为叫做方法的重写(覆盖,override)
  15. # 创建Dog类的实例
  16. # d = Dog()
  17. # d.run()
  18. # 当我们调用一个对象的方法时,
  19. # 会优先去当前对象中寻找是否具有该方法,如果有则直接调用
  20. # 如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法,
  21. # 如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错
  22. class A(object):
  23. def test(self):
  24. print('AAA')
  25. class B(A):
  26. def test(self):
  27. print('BBB')
  28. class C(B):
  29. def test(self):
  30. print('CCC')
  31. # 创建一个c的实例
  32. c = C()
  33. c.test()

super()

super() 可以用来动态获取当前类的父类

  1. class Animal:
  2. def __init__(self,name):
  3. self._name = name
  4. def run(self):
  5. print('动物会跑~~~')
  6. def sleep(self):
  7. print('动物睡觉~~~')
  8. @property
  9. def name(self):
  10. return self._name
  11. @name.setter
  12. def name(self,name):
  13. self._name = name
  14. # 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
  15. class Dog(Animal):
  16. def __init__(self,name,age):
  17. # 希望可以直接调用父类的__init__来初始化父类中定义的属性
  18. # super() 可以用来获取当前类的父类,
  19. # 并且通过super()返回对象调用父类方法时,不需要传递self
  20. super().__init__(name)#直接调用父类的__init__来初始化name属性
  21. self._age = age
  22. def bark(self):
  23. print('汪汪汪~~~')
  24. def run(self):
  25. print('狗跑~~~~')
  26. @property
  27. def age(self):
  28. return self._age
  29. @age.setter
  30. def age(self,age):
  31. self._age = age
  32. d = Dog('旺财',18)
  33. print(d.name)
  34. print(d.age)

多重继承
  1. class A(object):
  2. def test(self):
  3. print('AAA')
  4. class B(object):
  5. def test(self):
  6. print('B中的test()方法~~')
  7. def test2(self):
  8. print('BBB')
  9. # 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
  10. # 可以在类名的()后边添加多个类,来实现多重继承
  11. # 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
  12. # 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
  13. # 如果多个父类中有同名的方法,则会现在第一个父类中寻找,然后找第二个,然后找第三个。。。
  14. # 前边父类的方法会覆盖后边父类的方法
  15. class C(A,B):
  16. pass
  17. # 类名.__bases__ 这个属性可以用来获取当前类的所有父类
  18. # print(C.__bases__) (<class '__main__.B'>,)
  19. # print(B.__bases__) (<class 'object'>,)
  20. # print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)
  21. c = C()
  22. c.test()

多态

多态是面向对象的三大特征之一,多态从字面上理解是多种形态
狗:(狼狗、藏獒、哈士奇、古牧 。。。)一个对象可以以不同的形态去呈现

  1. # 定义两个类
  2. class A:
  3. def __init__(self,name):
  4. self._name = name
  5. @property
  6. def name(self):
  7. return self._name
  8. @name.setter
  9. def name(self,name):
  10. self._name = name
  11. class B:
  12. def __init__(self,name):
  13. self._name = name
  14. def __len__(self):
  15. return 10
  16. @property
  17. def name(self):
  18. return self._name
  19. @name.setter
  20. def name(self,name):
  21. self._name = name
  22. class C:
  23. pass
  24. a = A('孙悟空')
  25. b = B('猪八戒')
  26. c = C()
  27. # 定义一个函数
  28. # 对于say_hello()这个函数来说,只要对象中含有name属性,它就可以作为参数传递
  29. # 这个函数并不会考虑对象的类型,只要有name属性即可
  30. def say_hello(obj):
  31. print('你好 %s'%obj.name)
  32. # 在say_hello_2中我们做了一个类型检查,也就是只有obj是A类型的对象时,才可以正常使用,
  33. # 其他类型的对象都无法使用该函数,这个函数就违反了多态
  34. # 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型对象,这样导致函数的适应性非常的差
  35. # 注意,向isinstance()这种函数,在开发中一般是不会使用的!
  36. def say_hello_2(obj):
  37. # 做类型检查
  38. if isinstance(obj , A):
  39. print('你好 %s'%obj.name)
  40. say_hello(b) #可以调用
  41. say_hello_2(b) #不能调用
  42. # 鸭子类型
  43. # 如果一个东西,走路像鸭子,叫声像鸭子,那么它就是鸭子
  44. # len()
  45. # 之所以一个对象能通过len()来获取长度,是因为对象中具有一个特殊方法__len__
  46. # 换句话说,只要对象中具有__len__特殊方法,就可以通过len()来获取它的长度
  47. l = [1,2,3]
  48. s = 'hello'
  49. # print(len(l))
  50. # print(len(s))
  51. print(len(b)) #可以调用
  52. print(len(c)) #不能调用

面向对象的三大特征:

  1. 封装
  2. - 确保对象中的数据安全
  3. 继承
  4. - 保证了对象的可扩展性
  5. 多态
  6. - 保证了程序的灵活性

类的总结

类属性
  1. # 定义一个类
  2. class A(object):
  3. count = 0
  4. # 类属性,直接在类中定义的属性是类属性
  5. # 类属性可以通过类或类的实例访问到
  6. # 但是类属性只能通过类对象来修改,无法通过实例对象修改
  7. a = A()
  8. print(A ,A.count) #可以访问
  9. print(a ,a.count) #可以访问
  10. a.count = 10 #无法通过实例对象修改,只影响a(实例)的属性

实例属性
  1. class A(object):
  2. count = 0
  3. def __init__(self):
  4. self.name = '孙悟空'
  5. # 实例属性,通过实例对象添加的属性属于实例属性
  6. # 实例属性只能通过实例对象来访问和修改,类对象无法访问修改

实例方法
  1. class A(object):
  2. count = 0
  3. def __init__(self):
  4. self.name = '孙悟空'
  5. # 实例方法
  6. # 在类中定义,以self为第一个参数的方法都是实例方法
  7. # 实例方法在调用时,Python会将调用对象作为self传入
  8. # 实例方法可以通过实例和类去调用
  9. # 当通过实例调用时,会自动将当前调用对象作为self传入
  10. # 当通过类调用时,不会自动传递self,此时我们必须手动传递self
  11. def test(self):
  12. print('这是test方法~~~ ' , self)

类方法
  1. class A(object):
  2. count = 0
  3. def __init__(self):
  4. self.name = '孙悟空'
  5. def test(self):
  6. print('这是test方法~~~ ' , self)
  7. # 类方法
  8. # 在类内部使用 @classmethod 来修饰的方法属于类方法
  9. # 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
  10. # 类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
  11. # 类方法可以通过类去调用,也可以通过实例调用,没有区别
  12. @classmethod
  13. def test_2(cls):
  14. print('这是test_2方法,他是一个类方法~~~ ',cls)
  15. print(cls.count)

静态方法
  1. class A(object):
  2. count = 0
  3. def __init__(self):
  4. self.name = '孙悟空'
  5. def test(self):
  6. print('这是test方法~~~ ' , self)
  7. @classmethod
  8. def test_2(cls):
  9. print('这是test_2方法,他是一个类方法~~~ ',cls)
  10. print(cls.count)
  11. # 静态方法
  12. # 在类中使用 @staticmethod 来修饰的方法属于静态方法
  13. # 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
  14. # 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
  15. # 静态方法一般都是一些工具方法,和当前类无关
  16. @staticmethod
  17. def test_3():
  18. print('test_3执行了~~~')

垃圾回收

就像我们生活中会产生垃圾一样,程序在运行过程当中也会产生垃圾,程序运行过程中产生的垃圾会影响到程序的运行的运行性能,所以这些垃圾必须被及时清理

没用的东西就是垃圾,在程序中没有被引用的对象就是垃圾,这种垃圾对象过多以后会影响到程序的运行的性能,所以我们必须进行及时的垃圾回收,所谓的垃圾回收就是讲垃圾对象从内存中删除

在Python中有自动的垃圾回收机制,它会自动将这些没有被引用的对象删除,所以我们不用手动处理垃圾回收

  1. class A:
  2. def __init__(self):
  3. self.name = 'A类'
  4. # del是一个特殊方法,它会在对象被垃圾回收前调用
  5. def __del__(self):
  6. print('A()对象被删除了~~~',self)
  7. a = A()
  8. b = a # 又使用一个变量b,来引用a对应的对象
  9. print(a.name)
  10. # a = None # 将a设置为了None,此时没有任何的变量对A()对象进行引用,它就是变成了垃圾
  11. # b = None

特殊方法

特殊方法,也称为魔术方法, 特殊方法都是使用__开头和结尾的
特殊方法一般不需要我们手动调用,需要在一些特殊情况下自动执行

  1. # 定义一个Person类
  2. class Person(object):
  3. """人类"""
  4. def __init__(self, name , age):
  5. self.name = name
  6. self.age = age
  7. # __str__()这个特殊方法会在尝试将对象转换为字符串的时候调用
  8. # 它的作用可以用来指定对象转换为字符串的结果 (print函数)
  9. def __str__(self):
  10. return 'Person [name=%s , age=%d]'%(self.name,self.age)
  11. # __repr__()这个特殊方法会在对当前对象使用repr()函数时调用
  12. # 它的作用是指定对象在 ‘交互模式’中直接输出的效果
  13. def __repr__(self):
  14. return 'Hello'
  15. #一系列特殊方法
  16. # object.__add__(self, other)
  17. # object.__sub__(self, other)
  18. # object.__mul__(self, other)
  19. # object.__matmul__(self, other)
  20. # object.__truediv__(self, other)
  21. # object.__floordiv__(self, other)
  22. # object.__mod__(self, other)
  23. # object.__divmod__(self, other)
  24. # object.__pow__(self, other[, modulo])
  25. # object.__lshift__(self, other)
  26. # object.__rshift__(self, other)
  27. # object.__and__(self, other)
  28. # object.__xor__(self, other)
  29. # object.__or__(self, other)
  30. # object.__lt__(self, other) 小于 <
  31. # object.__le__(self, other) 小于等于 <=
  32. # object.__eq__(self, other) 等于 ==
  33. # object.__ne__(self, other) 不等于 !=
  34. # object.__gt__(self, other) 大于 >
  35. # object.__ge__(self, other) 大于等于 >=
  36. # __len__()获取对象的长度
  37. # object.__bool__(self)
  38. # 可以通过bool来指定对象转换为布尔值的情况
  39. def __bool__(self):
  40. return self.age > 17
  41. # __gt__会在对象做大于比较的时候调用,该方法的返回值将会作为比较的结果
  42. # 他需要两个参数,一个self表示当前对象,other表示和当前对象比较的对象
  43. # self > other
  44. def __gt__(self , other):
  45. return self.age > other.age
  46. # 创建两个Person类的实例
  47. p1 = Person('孙悟空',18)
  48. p2 = Person('猪八戒',28)
  49. # 打印p1
  50. # 当我们打印一个对象时,实际上打印的是对象的中特殊方法 __str__()的返回值
  51. # print(p1) # <__main__.Person object at 0x04E95090>
  52. # print(p1)
  53. # print(p2)
  54. # print(repr(p1))
  55. # t = 1,2,3
  56. # print(t) # (1, 2, 3)
  57. # print(p1 > p2)
  58. # print(p2 > p1)
  59. # print(bool(p1))
  60. # if p1 :
  61. # print(p1.name,'已经成年了')
  62. # else :
  63. # print(p1.name,'还未成年了')

模块

模块的创建和引入

模块(module)模块化,模块化指将一个完整的程序分解为一个一个小的模块
通过将模块组合,来搭建出一个完整的程序

不采用模块化,统一将所有的代码编写到一个文件中 .采用模块化,将程序分别编写到多个文件中

模块化的优点: ① 方便开发 ② 方便维护 ③ 模块可以复用!

在Python中一个py文件就是一个模块,要想创建模块,实际上就是创建一个python文件。
注意:模块名要符号标识符的规范。

在一个模块中引入外部模块
① import 模块名 (模块名,就是python文件的名字,注意不要py)。
② import 模块名 as 模块别名。

  • 可以引入同一个模块多次,但是模块的实例只会创建一个。
  • import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头。
  • 在每一个模块内部都有一个name属性,通过这个属性可以获取到模块的名字。
  • name属性值为 main的模块是主模块,一个程序中只会有一个主模块。主模块就是我们直接通过 python 执行的模块

引入一个叫test_module的模块:

  1. import test_module as test
  2. # print(test.__name__)
  3. print(__name__) #获取到模块的名字: __main__

模块的使用

创建一个模块:m.py

  1. # 可以在模块中定义变量,在模块中定义的变量,在引入模块后,就可以直接使用了
  2. a = 10
  3. b = 20
  4. # 添加了_的变量,只能在模块内部访问,在通过import * 引入时,不会引入_开头的变量
  5. _c = 30
  6. # 可以在模块中定义函数,同样可以通过模块访问到
  7. def test():
  8. print('test')
  9. def test2():
  10. print('test2')
  11. # 也可以定义类
  12. class Person:
  13. def __init__(self):
  14. self.name = '孙悟空'
  15. # 编写测试代码,这部分代码,只要当当前文件作为主模块的时候才需要执行
  16. # 而当模块被其他模块引入时,不需要执行的,此时我们就必须要检查当前模块是否是主模块
  17. if __name__ == '__main__':
  18. test()
  19. test2()
  20. p = Person()
  21. print(p.name)

主程序:

  1. import m #引入模块
  2. # # 访问模块中的变量:模块名.变量名
  3. # # print(m.a , m.b)
  4. # # m.test2()
  5. # p = m.Person()
  6. # print(p.name)
  7. def test2():
  8. print('这是主模块中的test2')
  9. # 也可以只引入模块中的部分内容
  10. # 语法 from 模块名 import 变量,变量....
  11. from m import Person
  12. from m import test
  13. from m import Person,test
  14. from m import * # 引入到模块中所有内容,一般不会使用
  15. p1 = Person()
  16. print(p1)
  17. test()
  18. test2()
  19. # 也可以为引入的变量使用别名
  20. # 语法:from 模块名 import 变量 as 别名
  21. from m import test2 as new_test2
  22. test2()
  23. new_test2()
  24. from m import *
  25. # print(_c)

包 Package。包也是一个模块
当我们模块中代码过多时,或者一个模块需要被分解为多个模块时,这时就需要使用到包。

普通的模块就是一个py文件,而包是一个文件夹
包中必须要一个一个 init.py 这个文件,这个文件中可以包含有包中的主要内容

Python笔记 - 图5

引入一个叫hello的包。

  1. from hello import a , b
  2. print(a.c)
  3. print(b.d)
  1. # __pycache__ 是模块的缓存文件
  2. # py代码在执行前,需要被解析器先转换为机器码,然后再执行
  3. # 所以我们在使用模块(包)时,也需要将模块的代码先转换为机器码然后再交由计算机执行
  4. # 而为了提高程序运行的性能,python会在编译过一次以后,将代码保存到一个缓存文件中
  5. # 这样在下次加载这个模块(包)时,就可以不再重新编译而是直接加载缓存中编译好的代码即可

python标准库

开箱即用。为了实现开箱即用的思想,Python中为我们提供了一个模块的标准库。
在这个标准库中,有很多很强大的模块我们可以直接使用,并且标准库会随Python的安装一同安装。

sys模块

  1. # sys模块,它里面提供了一些变量和函数,使我们可以获取到Python解析器的信息
  2. # 或者通过函数来操作Python解析器
  3. # 引入sys模块
  4. import sys
  5. # sys.argv
  6. # 获取执行代码时,命令行中所包含的参数
  7. # 该属性是一个列表,列表中保存了当前命令的所有参数
  8. print(sys.argv)
  9. # sys.path
  10. # 他是一个列表,列表中保存的是模块的搜索路径
  11. # ['C:\\Users\\lilichao\\Desktop\\resource\\course\\lesson_06\\code',
  12. # 'C:\\dev\\python\\python36\\python36.zip',
  13. # 'C:\\dev\\python\\python36\\DLLs',
  14. # 'C:\\dev\\python\\python36\\lib',
  15. # 'C:\\dev\\python\\python36',
  16. # 'C:\\dev\\python\\python36\\lib\\site-packages']
  17. print.pprint(sys.path)
  18. # sys.platform
  19. # 表示当前Python运行的平台
  20. print(sys.platform)
  21. # sys.exit()
  22. # 函数用来退出程序
  23. # sys.exit('程序出现异常,结束!')
  24. print('hello')

pprint 模块

  1. # pprint 模块它给我们提供了一个方法 pprint() 该方法可以用来对打印的数据做简单的格式化
  2. import pprint
  3. # sys.modules
  4. # 获取当前程序中引入的所有模块
  5. # modules是一个字典,字典的key是模块的名字,字典的value是模块对象
  6. pprint.pprint(sys.modules)

os模块

  1. # os 模块让我们可以对操作系统进行访问
  2. import os
  3. # os.environ
  4. # 通过这个属性可以获取到系统的环境变量
  5. pprint.pprint(os.environ['path'])
  6. # os.system()
  7. # 可以用来执行操作系统的名字
  8. # os.system('dir')
  9. os.system('notepad')

第七部分 异常和文件

异常

什么是异常

程序在运行过程当中,不可避免的会出现一些错误,比如:
使用了没有赋值过的变量
使用了不存在的索引
除0

这些错误在程序中,我们称其为异常。
程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全部都不会执行!

处理异常

程序运行时出现异常,目的并不是让我们的程序直接终止!
Python是希望在出现异常时,我们可以编写代码来对异常进行处理!

try语句
  1. try语句
  2. try:
  3. 代码块(可能出现错误的语句)
  4. except 异常类型 as 异常名:
  5. 代码块(出现错误以后的处理方式)
  6. except 异常类型 as 异常名:
  7. 代码块(出现错误以后的处理方式)
  8. except 异常类型 as 异常名:
  9. 代码块(出现错误以后的处理方式)
  10. else
  11. 代码块(没出错时要执行的语句)
  12. finally:
  13. 代码块(该代码块总会执行)
  14. # try是必须的 else语句有没有都行 except和finally至少有一个

如果出现错误,则会执行expect子句中的代码,这样我们就可以通过代码来处理异常
避免因为一个异常导致整个程序的终止

异常的传播

当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,。如果函数中没有对异常进行处理,则异常会继续向函数调用处传播,

如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播,直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息。

异常的对象

当程序运行过程中出现异常以后,所有的异常信息会被保存一个专门的异常对象中,而异常传播时,实际上就是异常对象抛给了调用处
比如 : ZeroDivisionError类的对象专门用来表示除0的异常, NameError类的对象专门用来处理变量错误的异常(在Python为我们提供了多个异常对象 )

  1. print('异常出现前')
  2. l = []
  3. try:
  4. # print(c)
  5. # l[10]
  6. # 1 + 'hello'
  7. print(10/0)
  8. except NameError:
  9. # 如果except后不跟任何的内容,则此时它会捕获到所有的异常
  10. # 如果在except后跟着一个异常的类型,那么此时它只会捕获该类型的异常
  11. print('出现 NameError 异常')
  12. except ZeroDivisionError:
  13. print('出现 ZeroDivisionError 异常')
  14. except IndexError:
  15. print('出现 IndexError 异常')
  16. # Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常
  17. # 可以在异常类后边跟着一个 as xx 此时xx就是异常对象
  18. except Exception as e :
  19. print('未知异常',e,type(e))
  20. finally :
  21. print('无论是否出现异常,该子句都会执行')
  22. print('异常出现后')

抛出异常

可以使用 raise 语句来抛出异常,raise语句后需要跟一个异常类 或 异常的实例

  1. class MyError(Exception):
  2. pass
  3. def add(a,b):
  4. # 如果a和b中有负数,就向调用处抛出异常
  5. if a < 0 or b < 0:
  6. # raise用于向外部抛出异常,后边可以跟一个异常类,或异常类的实例
  7. # raise Exception
  8. # 抛出异常的目的,告诉调用者这里调用时出现问题,希望你自己处理一下
  9. # raise Exception('两个参数中不能有负数!')
  10. raise MyError('自定义的异常')
  11. # 也可以通过if else来代替异常的处理
  12. # return None
  13. r = a + b
  14. return r
  15. print(add(-123,456))

文件(File)

通过Python程序来对计算机中的各种文件进行增删改查的操作 I/O(Input / Output)

操作文件的步骤:

  1. 打开文件<br /> 对文件进行各种操作(读、写),然后保存<br /> 关闭文件

打开文件

当前文件结构:

Python笔记 - 图6

使用open函数来打开一个文件:

  1. open(file, mode='r', buffering=-1, encoding_=None, errors=None, newline=None, closefd=True, opener=None)
  2. # 使用open函数来打开一个文件
  3. # 参数:
  4. # file 要打开的文件的名字(路径)
  5. # 返回值:
  6. # 返回一个对象,这个对象就代表了当前打开的文件
  7. # 创建一个变量,来保存文件的名字
  8. # 如果目标文件和当前文件在同一级目录下,则直接使用文件名即可
  9. file_name = 'demo.txt'
  10. # 在windows系统使用路径时,可以使用/来代替 \
  11. # 或者可以使用 \\ 来代替 \
  12. # 或者也可以使用原始字符串(加r)
  13. file_name = 'hello\\demo.txt'
  14. file_name = r'hello\demo.txt'
  15. # 表示路径,可以使用..来返回一级目录
  16. file_name = '../hello/demo.txt'
  17. # 如果目标文件距离当前文件比较远,此时可以使用绝对路径
  18. # 绝对路径应该从磁盘的根目录开始书写
  19. file_name = r'C:\Users\lilichao\Desktop\hello.txt'
  20. file_obj = open(file_name) # 打开 file_name 对应的文件
  21. print(file_obj)

打开文件代码基本结构:

  1. # 打开文件
  2. file_name = 'demo.txt'
  3. # 调用open()来打开文件
  4. file_obj = open(file_name)
  5. # # 当我们获取了文件对象以后,所有的对文件的操作都应该通过对象来进行
  6. # # 读取文件中的内容
  7. # # read()方法,用来读取文件中的内容,它会将内容全部保存为一个字符串返回
  8. content = file_obj.read()
  9. print(content)

关闭文件

调用close()方法来关闭文件

  1. # # 关闭文件
  2. # # 调用close()方法来关闭文件
  3. file_obj.close() #不常用
  4. # with ... as 语句
  5. with open(file_name) as file_obj :
  6. # # 在with语句中可以直接使用file_obj来做文件操作
  7. # # 此时这个文件只能在with中使用,一旦with结束则文件会自动close()
  8. # print(file_obj.read())

完善结构:

  1. file_name = 'hello'
  2. try:
  3. with open(file_name) as file_obj :
  4. print(file_obj.read())
  5. except FileNotFoundError:
  6. print(f'{file_name} 文件不存在~~')

文件读取

注意:
调用open()来打开一个文件,可以将文件分成两种类型:
一种,是纯文本文件(使用utf-8等编码编写的文本文件)
一种,是二进制文件(图片、mp3、ppt等这些文件)

open()打开文件时,默认是以文本文件的形式打开的,但是open()默认的编码为None
所以处理文本文件时,必须要指定文件的编码

  1. with open(file_name,encoding='utf-8') as file_obj:

通过 read() 来读取文件中的内容
  1. content = file_obj.read(6)
  2. content = file_obj.read(-1)

如果直接调用read()它会将文本文件的所有内容全部都读取出来,如果要读取的文件较大的话,会一次性将文件的内容加载到内存中,容易导致内存泄漏,所以对于较大的文件,不要直接调用read()

  1. file_name = 'demo2.txt'
  2. try:
  3. with open(file_name,encoding='utf-8') as file_obj:
  4. # content = file_obj.read(-1)
  5. content = file_obj.read(6)
  6. content = file_obj.read(6)
  7. content = file_obj.read(6)
  8. content = file_obj.read(6)
  9. # print(content)
  10. # print(len(content))
  11. except FileNotFoundError :
  12. print(f'{file_name} 这个文件不存在!')

read()可以接收一个size作为参数,该参数用来指定要读取的字符的数量, 默认值为-1,它会读取文件中的所有字符,可以为size指定一个值,这样read()会读取指定数量的字符。

每一次读取都是从上次读取到位置开始读取的,如果字符的数量小于size,则会读取剩余所有的,如果已经读取到了文件的最后了,则会返回’’空串

读取大文件的方式
  1. # 读取大文件的方式
  2. file_name = 'demo.txt'
  3. try:
  4. with open(file_name,encoding='utf-8') as file_obj:
  5. # 定义一个变量,来保存文件的内容
  6. file_content = ''
  7. # 定义一个变量,来指定每次读取的大小
  8. chunk = 100
  9. # 创建一个循环来读取文件内容
  10. while True:
  11. # 读取chunk大小的内容
  12. content = file_obj.read(chunk)
  13. # 检查是否读取到了内容
  14. if not content:
  15. # 内容读取完毕,退出循环
  16. break
  17. # 输出内容
  18. # print(content,end='')
  19. file_content += content
  20. except FileNotFoundError :
  21. print(f'{file_name} 这个文件不存在!')
  22. print(file_content)

其它读取方式:

readline() readlines()

  1. import pprint
  2. import os
  3. file_name = 'demo.txt'
  4. with open(file_name , encoding='utf-8') as file_obj:
  5. # readline()
  6. # 该方法可以用来读取一行内容
  7. print(file_obj.readline(),end='')
  8. # print(file_obj.readline())
  9. # print(file_obj.readline())
  10. # readlines()
  11. # 该方法用于一行一行的读取内容,它会一次性将读取到的内容封装到一个列表中返回
  12. r = file_obj.readlines()
  13. pprint.pprint(r[0])
  14. # pprint.pprint(r[1])
  15. # pprint.pprint(r[2])
  16. for t in file_obj:
  17. print(t)d

二进制文件的读取
  1. file_name = 'c:/Users/lilichao/Desktop/告白气球.flac'#读取一个音乐文件
  2. # 读取模式
  3. # t 读取文本文件(默认值)
  4. # b 读取二进制文件
  5. with open(file_name , 'rb') as file_obj:
  6. # 读取文本文件时,size是以字符为单位的
  7. # 读取二进制文件时,size是以字节为单位
  8. # print(file_obj.read(100))

将读取到的内容写出来

  1. # 将读取到的内容写出来
  2. # 定义一个新的文件
  3. new_name = 'aa.flac'
  4. with open(new_name , 'wb') as new_obj:
  5. # 定义每次读取的大小
  6. chunk = 1024 * 100 #每次读取100K
  7. while True :
  8. # 从已有的对象中读取数据
  9. content = file_obj.read(chunk)
  10. # 内容读取完毕,终止循环
  11. if not content :
  12. break
  13. # 将读取到的数据写入到新对象中
  14. new_obj.write(content)

文件的写入

  1. file_name = 'demo5.txt'
  2. # 使用open()打开文件时必须要指定打开文件所要做的操作(读、写、追加)
  3. # 如果不指定操作类型,则默认是 读取文件 , 而读取文件时是不能向文件中写入的
  4. # r 表示只读的 (默认值)
  5. # w 表示是可写的,使用w来写入文件时,如果文件不存在会创建文件,如果文件存在则会截断文件
  6. # 截断文件指删除原来文件中的所有内容
  7. # a 表示追加内容,如果文件不存在会创建文件,如果文件存在则会向文件中追加内容
  8. # x 用来新建文件,如果文件不存在则创建,存在则报错
  9. # + 为操作符增加功能
  10. # r+ 即可读又可写,文件不存在会报错
  11. # w+
  12. # a+
  13. # with open(file_name , 'w' , encoding='utf-8') as file_obj:
  14. # with open(file_name , 'r+' , encoding='utf-8') as file_obj:
  15. with open(file_name , 'x' , encoding='utf-8') as file_obj:
  16. # write()来向文件中写入内容,
  17. # 如果操作的是一个文本文件的话,则write()需要传递一个字符串作为参数
  18. # 该方法会可以分多次向文件中写入内容
  19. # 写入完成以后,该方法会返回写入的字符的个数
  20. file_obj.write('aaa\n')
  21. file_obj.write('bbb\n')
  22. file_obj.write('ccc\n')
  23. r = file_obj.write(str(123)+'123123\n')
  24. r = file_obj.write('今天天气真不错')
  25. print(r)

读取文件的位置

  1. # with open('demo.txt','rb') as file_obj:
  2. # # print(file_obj.read(100))
  3. # # print(file_obj.read(30))
  4. # # seek() 可以修改当前读取的位置
  5. # file_obj.seek(55)
  6. # file_obj.seek(80,0)
  7. # file_obj.seek(70,1)
  8. # file_obj.seek(-10,2)
  9. # # seek()需要两个参数
  10. # # 第一个 是要切换到的位置
  11. # # 第二个 计算位置方式
  12. # # 可选值:
  13. # # 0 从头计算,默认值
  14. # # 1 从当前位置计算
  15. # # 2 从最后位置开始计算
  16. # print(file_obj.read())
  17. # # tell() 方法用来查看当前读取的位置
  18. # print('当前读取到了 -->',file_obj.tell())
  19. with open('demo2.txt','rt' , encoding='utf-8') as file_obj:
  20. # print(file_obj.read(100))
  21. # print(file_obj.read(30))
  22. # seek() 可以修改当前读取的位置
  23. file_obj.seek(9)
  24. # seek()需要两个参数
  25. # 第一个 是要切换到的位置
  26. # 第二个 计算位置方式
  27. # 可选值:
  28. # 0 从头计算,默认值
  29. # 1 从当前位置计算
  30. # 2 从最后位置开始计算
  31. print(file_obj.read())
  32. # tell() 方法用来查看当前读取的位置
  33. print('当前读取到了 -->',file_obj.tell())

文件的其他操作(和操作系统命令行相似)

  1. import os
  2. from pprint import pprint
  3. # os.listdir() 获取指定目录的目录结构
  4. # 需要一个路径作为参数,会获取到该路径下的目录结构,默认路径为 . 当前目录
  5. # 该方法会返回一个列表,目录中的每一个文件(夹)的名字都是列表中的一个元素
  6. r = os.listdir()
  7. # os.getcwd() 获取当前所在的目录
  8. r = os.getcwd()
  9. # os.chdir() 切换当前所在的目录 作用相当于 cd
  10. # os.chdir('c:/')
  11. # r = os.getcwd()
  12. # 创建目录
  13. # os.mkdir("aaa") # 在当前目录下创建一个名字为 aaa 的目录
  14. # 删除目录
  15. # os.rmdir('abc')
  16. # open('aa.txt','w')
  17. # 删除文件
  18. # os.remove('aa.txt')
  19. # os.rename('旧名字','新名字') 可以对一个文件进行重命名,也可以用来移动一个文件
  20. # os.rename('aa.txt','bb.txt')
  21. os.rename('bb.txt','c:/users/lilichao/desktop/bb.txt')
  22. pprint(r)

END:Duruofu 2022.4.27于西安理工大学