Python入门笔记(Duruofu)
第一部分 计算机基础知识(了解即可)
计算机的组成
计算机由两部分组成:硬件 和 软件
硬件包含:键盘、鼠标、显示器、CPU、主板、内存、硬盘 。。。硬件是看的见摸得着的
软件包含:系统软件(windows、macOS、Linux)和应用软件(office 、QQ、绝地求生)软件是看的见摸不着的,软件负责控制计算机中的硬件
计算机的使用方式
我们必须要通过软件来对计算机完成各种操作,但是注意,软件中并不是所有的功能都会对用户开放,用户需要调用软件提供的接口(Interface 交互界面)来操作计算机
用户界面分成两种:TUI(文本交互界面)和 GUI(图形化交互界面)
windows的命令行
命令行就是文本交互界面,通过命令行可以使用一个一个的指令来操作计算机,任何的计算机的操作系统中都包含有命令行(windows、linux、macOS)
命令行有多个不同的名字:命令行、命令行窗口、DOS窗口、命令提示符、CMD窗口、Shell、终端、Terminal
1.如何进入到命令行
win键 + R 出现运行窗口,输入cmd,然后回车

2.命令行的结构
- 版本及版权声明(一般没有什么用)Microsoft Windows [版本 10.0.16299.431](c) 2017 Microsoft Corporation。保留所有权利。命令提示符C:\Users\lilichao>C:- 当前所在的磁盘根目录- 可以通过 x: 来切换盘符(x表示你的盘符)\Users\lilichao- 所在磁盘的路径,当前所在的文件夹- cd 来切换目录>- 命令提示符,在大于号后边可以直接输入指令
3.常用的dos命令
dir 查看当前目录下的所有文件(夹)<br /> cd 进入到指定的目录<br /> . 表示当前目录<br /> .. 表示上一级目录<br /> md 创建一个目录<br /> rd 删除一个目录<br /> del 删除一个文件<br /> cls 清除屏幕<br />命令的语法<br /> 命令 [参数] [选项]
4.小技巧
- 方向键上下,查看命令的历史记录
- tab键自动补全命令
环境变量
环境变量指的就是操作系统当中的一些变量。可以通过修改环境变量,来对计算机进行配置(主要是来配置一些路径的)
1.查看环境变量
> 右键 计算机(此电脑),选择属性<br /> > 系统界面左侧选择 高级系统设置<br /> > 选择环境变量<br /> 环境变量界面分成了两个部分,上边是用户环境变量,下边是系统环境变量 建议只修改用户的环境变量,不要修改系统的环境变量
2.添加环境变量
> 通过新建按钮添加环境变量<br /> > 一个环境变量可以由多个值,值与值之间使用;(英文)隔开
3.修改环境变量
> 通过编辑按钮来修改环境变量
4.删除环境变量
> 通过删除按钮来删除环境变量
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 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)] on win32Type "help", "copyright", "credits" or "license" for more information.命令提示符:>>>在命令提示符后可以直接输入Python的指令!输入完的指令将会被Python的解释器立即执行!安装Python的同时,会自动安装一个Python的开发工具IDLE,通过IDLE也可以进入到交互模式但是不同的是,在IDLE中可以通过TAB键来查看语句的提示。IDLE实际上就是一个交互界面,但是他可以有一些简单的提示,并且可以将代码保存
交互模式只能你输入一行代码,它就是执行一行,所以他并不适用于我们日常的开发!
仅可以用来做一些日常的简单的测试!
我们一般会将Python代码编写到一个py文件中,然后通过python指令来执行文件中的代码
相关概念
1.表达式
表达式就是一个类似于数学公式的东西<br /> 比如:10 + 5 8 - 4<br /> 表达式一般仅仅用了计算一些结果,不会对程序产生实质性的影响<br /> 如果在交互模式中输入一个表达式,解释器会自动将表达式的结果输出
2.语句
在程序中语句一般需要完成某种功能,比如打印信息、获取信息、为变量赋值。。。<br /> 比如:<br /> print()<br /> input()<br /> a = 10<br /> 语句的执行一般会对程序产生一定的影响<br /> 在交互模式中不一定会输出语句的执行结果
3.程序(program)
程序就是由一条一条的语句和一条一条的表达式构成的。
4.函数(function)
函数就是一种语句,函数专门用来完成特定的功能<br /> 函数长的形如:xxx()
函数的分类:
内置函数:
由Python解释器提供的函数,可以在Python中直接使用
自定义函数
由程序员自主的创建的函数<br /> 当我们需要完成某个功能时,就可以去调用内置函数,或者自定义函数
函数的两个要素:
**参数**<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)变量可以用来保存字面量,并且变量中保存的字面量是不定的。变量本身没有任何意思,它会根据不同的字面量表示不同的意思
一般我们在开发时,很少直接使用字面量,都是将字面量保存到变量中,通过变量来引用字面量
变量和标识符
# Python中使用变量,不需要声明,直接为变量赋值即可a = 10# 不能使用没有进行过赋值的变量# 如果使用没有赋值过的变量,会报错 NameError: name 'b' is not defined# print(b)# Python是一个动态类型的语言,可以为变量赋任意类型的值,也可以任意修改变量的值a = 'hello'# print(a)# 标识符# 在Python中所有可以自主命名的内容都属于标识符# 比如:变量名、函数名、类名# 标识符必须遵循标识符的规范# 1.标识符中可以含有字母、数字、_,但是不能使用数字开头# 例子:a_1 _a1 _1a# 2.标识符不能是Python中的关键字和保留字# 也不建议使用Python中的函数名作为标识符,因为这样会导致函数被覆盖# 3.命名规范:# 在Python中注意遵循两种命名规范:# 下划线命名法# 所有字母小写,单词之间使用_分割# max_length min_length hello_world xxx_yyy_zzz# 帕斯卡命名法(大驼峰命名法)# 首字母大写,每个单词开头字母大写,其余字母小写# MaxLength MinLength HelloWorld XxxYyyZzz## 如果使用不符合标准的标识符,将会报错 SyntaxError: invalid syntax_b123 = 20# print(_b123)# print = 123# print(print)
数据类型
数据类型指的就是变量的值得类型,也就是可以为变量赋哪些值
1.数值:整型, 浮点型,复数
# 在Python数值分成了三种:整数、浮点数(小数)、复数# 在Python中所有的整数都是int类型a = 10b = 20# Python中的整数的大小没有限制,可以是一个无限大的整数# c = 999999999999999999999999999999999999999999999 ** 100# 如果数字的长度过大,可以使用下划线作为分隔符c = 123_456_789# d = 0123 10进制的数字不能以0开头# 其他进制的整数,只要是数字打印时一定是以十进制的形式显示的# 二进制 0b开头c = 0b10 # 二进制的10# 八进制 0o开头c = 0o10# 十六进制 0x开头c = 0x10# 也可以通过运算符来对数字进行运算,并且可以保证整数运算的精确c = -100c = c + 3# 浮点数(小数),在Python中所有的小数都是float类型c = 1.23c = 4.56# 对浮点数进行运算时,可能会得到一个不精确的结果c = 0.1 + 0.2 # 0.30000000000000004print(c)
2.字符串
字符串介绍:
# 字符串(str)# 字符串用来表示一段文本信息,字符串是程序中使用的最多的数据类型# 在Python中字符串需要使用引号引起来s = 'hello'# s = abc # 字符串必须使用引号引起来,不使用不是字符串# 引号可以是双引号,也可以是单引号,但是注意不要混着用s = 'hello's = "hello"# s = 'hello" 引号不能混合使用 SyntaxError: EOL while scanning string literal# 相同的引号之间不能嵌套# s = "子曰:"学而时习之,乐呵乐呵!""s = '子曰:"学而时习之,乐呵乐呵!"'# 长字符串# 单引号和双引号不能跨行使用s = '锄禾日当午,\汗滴禾下土,\谁知盘中餐,\粒粒皆辛苦'# 使用三重引号来表示一个长字符串 ''' """# 三重引号可以换行,并且会保留字符串中的格式s = '''锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦'''# 转义字符# 可以使用 \ 作为转义字符,通过转义字符,可以在字符串中使用一些特殊的内容# 例子:# \' 表示'# \" 表示"# \t 表示制表符# \n 表示换行符# \\ 表示反斜杠# \uxxxx 表示Unicode编码s = "子曰:\"学而时习之,\\\\n乐呵乐呵!\""s = '\u2250'print(s)
格式化字符串
# 格式化字符串a = 'hello'# 字符串之间也可以进行加法运算# 如果将两个字符串进行相加,则会自动将两个字符串拼接为一个a = 'abc' + 'haha' + '哈哈'# a = 123# 字符串只能不能和其他的类型进行加法运算,如果做了会出现异常 TypeError: must be str, not int# print("a = "+a) # 这种写法在Python中不常见a = 123# print('a =',a)# 在创建字符串时,可以在字符串中指定占位符# %s 在字符串中表示任意字符# %f 浮点数占位符# %d 整数占位符b = 'Hello %s'%'孙悟空'b = 'hello %s 你好 %s'%('tom','孙悟空')b = 'hello %3.5s'%'abcdefg' # %3.5s字符串的长度限制在3-5之间b = 'hello %s'%123.456b = 'hello %.2f'%123.456b = 'hello %d'%123.95b = '呵呵'# print('a = %s'%a)# 格式化字符串,可以通过在字符串前添加一个f来创建一个格式化字符串# 在格式化字符串中可以直接嵌入变量c = f'hello {a} {b}'print(f'a = {a}')
复制字符串
# 创建一个变量来保存你的名字name = '孙悟空'# 使用四种方式来输出,欢迎 xxx 光临# 拼串print('欢迎 '+name+' 光临!')# 多个参数print('欢迎',name,'光临!')# 占位符print('欢迎 %s 光临!'%name)# 格式化字符串print(f'欢迎 {name} 光临!')# 字符串的复制(将字符串和数字相乘)a = 'abc'# * 在语言中表示乘法# 如果将字符串和数字相乘,则解释器会将字符串重复指定的次数并返回a = a * 20print(a)
3.空值和布尔值
# 布尔值(bool)# 布尔值主要用来做逻辑判断# 布尔值一共有两个 True 和 False# True表示真 False表示假a = Truea = False# print('a =',a)# 布尔值实际上也属于整型,True就相当于1,False就相当于0# print(1 + False)# None(空值)# None专门用来表示不存在b = Noneprint(b)
类型检查
# 通过类型检查,可以检查只能值(变量)的类型a = 123 # 数值b = '123' # 字符串# print('a =',a)# print('b =',b)、# type()用来检查值的类型# 该函数会将检查的结果作为返回值返回,可以通过变量来接收函数的返回值c = type('123')c = type(a)# print(type(b))print(type(1)) # <class 'int'>print(type(1.5)) # <class 'float'>print(type(True)) # <class 'bool'>print(type('hello')) # <class 'str'>print(type(None)) # <class 'NoneType'>
对象(object)
- Python是一门面向对象的语言
- 一切皆对象!
- 程序运行当中,所有的数据都是存储到内存当中然后再运行的!
- 对象就是内存中专门用来存储指定数据的一块区域
- 对象实际上就是一个容器,专门用来存储数据
- 像我们之前学习的数值、字符串、布尔值、None都是对象
对象的结构
- 每个对象中都要保存三种数据
- id(标识)
id用来标识对象的唯一性,每一个对象都有唯一的id
对象的id就相当于人的身份证号一样
可以通过id()函数来查看对象的id
id是由解析器生成的,在CPython中,id就是对象的内存地址
对象一旦创建,则它的id永远不能再改变
- id(标识)
- type(类型)
类型用来标识当前对象所属的类型
比如:int str float bool 。。。
类型决定了对象有哪些功能
通过type()函数来查看对象的类型
Python是一门强类型的语言,对象一旦创建类型便不能修改
- value(值)
值就是对象中存储的具体的数据
对于有些对象值是可以改变的
对象分成两大类,可变对象 不可变对象
可变对象的值可以改变
不可变对象的值不能改变,之前学习的对象都是不可变对象
变量和对象
- 对象并没有直接存储到变量中,在Python中变量更像是给对象起了一个别名
- 变量中存储的不是对象的值,而是对象的id(内存地址),
当我们使用变量时,实际上就是在通过对象id在查找对象 - 变量中保存的对象,只有在为变量重新赋值时才会改变
- 变量和变量之间是相互独立的,修改一个变量不会影响另一个变量
类型转换
- 所谓的类型转换,将一个类型的对象转换为其他对象
- 类型转换不是改变对象本身的类型,而是根据当前对象的值创建一个新对象
# 类型转换四个函数 int() float() str() bool()# int() 可以用来将其他的对象转换为整型# 规则:# 布尔值:True -> 1 False -> 0# 浮点数:直接取整,省略小数点后的内容# 字符串:合法的整数字符串,直接转换为对应的数字# 如果不是一个合法的整数字符串,则报错 ValueError: invalid literal for int() with base 10: '11.5'# 对于其他不可转换为整型的对象,直接抛出异常 ValueError# float() 和 int()基本一致,不同的是它会将对象转换为浮点数# str() 可以将对象转换为字符串# True -> 'True'# False -> 'False'# 123 -> '123'# 。。。# bool() 可以将对象转换为布尔值,任何对象都可以转换为布尔值# 规则:对于所有表示空性的对象都会转换为False,其余的转换为True# 哪些表示的空性:0 、 None 、 '' 。。。a = True# 调用int()来将a转换为整型# int()函数不会对原来的变量产生影响,他是对象转换为指定的类型并将其作为返回值返回# 如果希望修改原来的变量,则需要对变量进行重新赋值a = int(a)a = Falsea = int(a)a = '123'a = int(a)a = 11.6a = int(a)a = '11.5'# a = int(a)a = None# a = int(a)a = 1a = float(a)a = Falsea = float(a)a = 123a = str(a)a = Nonea = bool(a)print('a =',a)print('a的类型是',type(a))# b = 456# print('hello'+str(b))
运算符(操作符)
- 运算符可以对一个值或多个值进行运算或各种操作
- 比如 + 、-、= 都属于运算符
运算符的分类:
1.算术运算符
# 算术运算符# + 加法运算符(如果是两个字符串之间进行加法运算,则会进行拼串操作)# - 减法运算符# * 乘法运算符(如果将字符串和数字相乘,则会对字符串进行复制操作,将字符串重复指定次数)# / 除法运算符,运算时结果总会返回一个浮点类型# // 整除,只会保留计算后的整数位,总会返回一个整型# ** 幂运算,求一个值的几次幂# % 取模,求两个数相除的余数a = 10 + 5 # 计算a = 'hello' + ' ' + 'world' # 拼串a = 10 - 5 # 计算a = 5 - Truea = a - 2 # 用变量a的值减去2,然后再赋值给a# a = 'hello' - 'h' TypeErrora = 5 * 5a = 10 / 5a = 5 / 2# a = 5 / 0 ZeroDivisionError: division by zeroa = 10 / 3a = 10 // 3a = 5 // 2a = 2 ** 2a = 10 ** 5a = 16 ** 0.5 # 求16的平方根a = 10 % 5 # 0a = 10 % 4 # 2a = 10 % 3 # 1a = 10 % 2 # 0print("a =",a)
2.赋值运算符
# 赋值运算符# = 可以将等号右侧的值赋值给等号左侧的变量# += a += 5 相当于 a = a + 5# -= a -= 5 相当于 a = a - 5# *= a *= 5 相当于 a = a * 5# **= a **= 5 相当于 a = a ** 5# /= a /= 5 相当于 a = a / 5# //= a //= 5 相当于 a = a // 5# %= a %= 5 相当于 a = a % 5a = 10# a = a + 5# a += 5a -= 5a *= 5a **= 2a /= 25a = 25.0 # 在对浮点数做算术运算时,结果也会返回一个浮点数a //= 5a = 5a %= 4print('a =',a)
3.比较运算符(关系运算符)
# 关系运算符# 关系运算符用来比较两个值之间的关系,总会返回一个布尔值# 如果关系成立,返回True,否则返回False# > 比较左侧值是否大于右侧值# >= 比较左侧的值是否大于或等于右侧的值# < 比较左侧值是否小于右侧值# <= 比较左侧的值是否小于或等于右侧的值# == 比较两个对象的值是否相等# != 比较两个对象的值是否不相等# 相等和不等比较的是对象的值,而不是id# is 比较两个对象是否是同一个对象,比较的是对象的id# is not 比较两个对象是否不是同一个对象,比较的是对象的idresult = 10 > 20 # Falseresult = 30 > 20 # Trueresult = 30 < 20 # Falseresult = 10 >= 10 # Trueresult = 2 > True # True# result = 2 > '1' TypeError: '>' not supported between instances of 'int' and 'str'# 0032 > 0031result = '2' > '1' # Trueresult = '2' > '11' # True# 在Python中可以对两个字符串进行大于(等于)或小于(等于)的运算,# 当对字符串进行比较时,实际上比较的是字符串的Unicode编码# 比较两个字符串的Unicode编码时,是逐位比较的# 利用该特性可以对字符串按照字母顺序进行排序,但是对于中文来说意义不是特别大# 注意:如果不希望比较两个字符串的Unicode编码,则需要将其转换为数字然后再比较# 0061 > 0062result = 'a' > 'b' # Falseresult = 'c' < 'd' # Trueresult = 'ab' > 'b' # False# print(int('2') > int('11'))result = 1 == 1 # Trueresult = 'hello' == 'hello' # Trueresult = 'abc' == 'bcd' # Falseresult = 'abc' != 'bcd' # Trueresult = 1 == True # Trueresult = 1 is True # Falseresult = 1 is not True # Trueprint('result =',result)print(id(1),id(True))
4.逻辑运算符
# 逻辑运算符# 逻辑运算符主要用来做一些逻辑判断# not 逻辑非# not可以对符号右侧的值进行非运算# 对于布尔值,非运算会对其进行取反操作,True变False,False变True# 对于非布尔值,非运算会先将其转换为布尔值,然后再取反## and 逻辑与# and可以对符号两侧的值进行与运算# 只有在符号两侧的值都为True时,才会返回True,只要有一个False就返回False# 与运算是找False的# Python中的与运算是短路的与,如果第一个值为False,则不再看第二个值## or 逻辑或# or 可以对符号两侧的值进行或运算# 或运算两个值中只要有一个True,就会返回True# 或运算是找True的# Python中的或运算是短路的或,如果第一个值为True,则不再看第二个值## 练习:# 尝试一下对布尔值进行三种逻辑运算# 尝试对非布尔值进行三种逻辑运算,并观察返回的结果#a = Truea = not a # 对a进行非运算a = 1a = ''a = not a# print('a =',a)result = True and True # Trueresult = True and False # Falseresult = False and True # Falseresult = False and False # False# print(result)# True and print('你猜我出来吗?') 第一个值是True,会看第二个值,所以print()会执行# False and print('你猜我出来吗?')第一个值是False,不会看第二个值,所以print()不会执行result = True or True # Trueresult = True or False # Trueresult = False or True # Trueresult = False or False # False# print(result)# False or print('你猜我出来吗?') 第一个值为False,继续看第二个,所以打印语句执行# True or print('你猜我出来吗?') 第一个值为True,不看第二个,所以打印语句不执行# 非布尔值的与或运算# 当我们对非布尔值进行与或运算时,Python会将其当做布尔值运算,最终会返回原值# 与运算的规则# 与运算是找False的,如果第一个值是False,则不看第二个值# 如果第一个值是False,则直接返回第一个值,否则返回第二个值# 或运算的规则# 或运算是找True的,如果第一个值是True,则不看第二个值# 如果第一个值是True,则直接返回第一个值,否则返回第二个值# True and Trueresult = 1 and 2 # 2# True and Falseresult = 1 and 0 # 0# False and Trueresult = 0 and 1 # 0# False and Falseresult = 0 and None # 0# True or Trueresult = 1 or 2 # 1# True or Falseresult = 1 or 0 # 1# False or Trueresult = 0 or 1 # 1# False or Falseresult = 0 or None # Noneprint(result)
5.条件运算符(三元运算符)
# 条件运算符(三元运算符)# 语法: 语句1 if 条件表达式 else 语句2# 执行流程:# 条件运算符在执行时,会先对条件表达式进行求值判断# 如果判断结果为True,则执行语句1,并返回执行结果# 如果判断结果为False,则执行语句2,并返回执行结果# 练习:# 现在有a b c三个变量,三个变量中分别保存有三个数值,# 请通过条件运算符获取三个值中的最大值# print('你好') if False else print('Hello')a = 30b = 50# print('a的值比较大!') if a > b else print('b的值比较大!')# 获取a和b之间的较大值max = a if a > b else bprint(max)
运算符的优先级
a = 40b = 50c = 30# 通过条件运算符获取三个值中的最大值# max = a if a > b else b# max = max if max > c else cmax = a if (a > b and a > c) else (b if b > c else c) # 不推荐这么使用# max = a if (b < a > c) else (b if b > c else c)# print(max)# 运算符的优先级# 和数学中一样,在Python运算也有优先级,比如先乘除 后加减# 运算符的优先级可以根据优先级的表格来查询,# 在表格中位置越靠下的运算符优先级越高,优先级越高的越优先计算# 如果优先级一样则自左向右计算# 关于优先级的表格,你知道有这么一个东西就够了,千万不要去记# 在开发中如果遇到优先级不清楚的,则可以通过小括号来改变运算顺序a = 1 + 2 * 3# 一样 and高 or高# 如果or的优先级高,或者两个运算符的优先级一样高# 则需要先进行或运算,则运算结果是3# 如果and的优先级高,则应该先计算与运算# 则运算结果是1a = 1 or 2 and 3# print(a)# 逻辑运算符(补充)# 逻辑运算符可以连着使用result = 1 < 2 < 3 # 相当于 1 < 2 and 2 < 3result = 10 < 20 > 15print(result)
第三部分 流程控制语句
Python代码在执行时是按照自上向下顺序执行的。通过流程控制语句,可以改变程序的执行顺序,也可以让指定的程序反复执行多次
流程控制语句分成两大类:条件判断语句,循环语句
条件判断语句(if语句)
if语句
# 条件判断语句(if语句)# 语法:if 条件表达式 :# 代码块# 执行的流程:if语句在执行时,会先对条件表达式进行求值判断,# 如果为True,则执行if后的语句# 如果为False,则不执行# 默认情况下,if语句只会控制紧随其后的那条语句,如果希望if可以控制多条语句,# 则可以在if后跟着一个代码块# 代码块# 代码块中保存着一组代码,同一个代码块中的代码,要么都执行要么都不执行# 代码块就是一种为代码分组的机制# 如果要编写代码块,语句就不能紧随在:后边,而是要写在下一行# 代码块以缩进开始,直到代码恢复到之前的缩进级别时结束# 鲁迅说过:# 世上本来没有路,走的人多了自然就有了!# xxxx# yyyy....# 缩进有两种方式,一种是使用tab键,一种是使用空格(四个)# Python的官方文档中推荐我们使用空格来缩进# Python代码中使用的缩进方式必须统一# "translate_tabs_to_spaces": true,# if False : print('你猜我出来么?')num = 10# if num > 10 : print('num比10大!')# print('谁也管不了我')if False :print(123)print(456)print(789)print(101112)# print('hello')num = 28# 可以使用逻辑运算符来连接多个条件,# 如果希望所有条件同时满足,则需要使用and# 如果希望只要有一个条件满足即可,则需要使用or# if num > 10 and num < 20 :# print('num比10大,num比20小!')# if 10 < num < 20 :# print('num比10大,num比20小!')# 在命令行让用户输入一个用户名,获取用户输入,并进行判断# 如果用户输入的用户名是admin,则显示欢迎管理员光临# 如果用户输入的是其他的用户名,则什么也不做username=input("输入用户名")if username=="admin":print("欢迎管理员光临")
input函数
# input()函数# 该函数用来获取用户的输入# input()调用后,程序会立即暂停,等待用户输入# 用户输入完内容以后,点击回车程序才会继续向下执行# 用户输入完成以后,其所输入的的内容会以返回值得形式返回# 注意:input()的返回值是一个字符串# input()函数中可以设置一个字符串作为参数,这个字符串将会作为提示文字显示# a = input('请输入任意内容:')# print('用户输入的内容是:',a)# input()也可以用于暂时阻止程序结束# 获取用户输入的用户名username = input('请输入你的用户名:')# 判断用户名是否是adminif username == 'admin' :print('欢迎管理员光临!')
if-else语句
让用户在控制台中输入一个年龄# age = int(input('请输入你的年龄:'))# 如果用户的年龄大于18岁,则显示你已经成年了# if age >= 18 :# print('你已经成年了~~~')# if-else语句# 语法:# if 条件表达式 :# 代码块# else :# 代码块# 执行流程:# if-else语句在执行时,先对if后的条件表达式进行求值判断# 如果为True,则执行if后的代码块# 如果为False,则执行else后的代码块age = 7if age > 17 :print('你已经成年了~~')else :print('你还未成年~~')
if-elif-else语句
# if-elif-else语句# 语法:# if 条件表达式 :# 代码块# elif 条件表达式 :# 代码块# elif 条件表达式 :# 代码块# elif 条件表达式 :# 代码块# else :# 代码块## 执行流程:# if-elif-else语句在执行时,会自上向下依次对条件表达式进行求值判断,# 如果表达式的结果为True,则执行当前代码块,然后语句结束# 如果表达式的结果为False,则继续向下判断,直到找到True为止# 如果所有的表达式都是False,则执行else后的代码块# if-elif-else中只会有一个代码块会执行age = 210# if age > 200 :# print('活着可真没劲呢!')# elif age > 100 :# print('你也是老大不小了!')# elif age >= 60 :# print('你已经退休了!')# elif age >= 30 :# print('你已经是中年了!')# elif age >= 18 :# print('你已经成年了!')# else :# print('你还是个小孩!')age = 68if age >= 18 and age < 30 :print('你已经成年了!')elif age >= 30 and age < 60 :print('你已经中年了!')elif age >= 60 :print('你已经退休了!')
练习
练习1:
编写一个程序,获取一个用户输入的整数。然后通过程序显示这个数是奇数还是偶数。
from cgi import print_formenter_an_integer = int(input('输入一个整数:'))print('你输入的整数是:',enter_an_integer)if enter_an_integer % 2 == 0:print('这个数是偶数')if enter_an_integer % 2 == 1:print('这个数是奇数')# 优化:# 获取用户输入的整数# num = int(input('请输入一个任意的整数:'))# print('你输入的整数是:',enter_an_integer)# # 显示num是奇数还是偶数# if num % 2 == 0 :# print(num , "是偶数")# else :# print(num , '是奇数')
练习2:
编写一个程序,检查任意一个年份是否是闰年。<br /> 如果一个年份可以被4整除不能被100整除,或者可以被400整除,这个年份就是闰年
year = int(input('输入一个年份'))#print('你输入的是',year)if year % 4 == 0 and year %100!=0 or year %400 == 0:print('这个年份是闰年')else:print('这个年份不是闰年')
练习3:
我家的狗5岁了,5岁的狗相当于多大年龄的人呢?<br /> 其实非常简单,狗的前两年每一年相当于人类的10.5岁,然后每增加一年就增加四岁。<br /> 那么5岁的狗相等于人类的年龄就应该是10.5+10.5+4+4+4 = 33岁<br /> 编写一个程序,获取用户输入的狗的年龄,然后通过程序显示其相当于人类的年龄。<br /> 如果用户输入负数,请显示一个提示信息
dog_age = float(input('请输入狗的年龄:'))print('狗的年龄是:',dog_age)if dog_age < 0 :print('你输入的',dog_age,'不是正确的年龄')elif dog_age <= 2 :dog_age = 10.5print('狗的年龄是:',dog_age)else :dog_age = 21+(dog_age-2)*4print('狗的年龄是',dog_age)# 优化解答# dog_age = float(input('请输入狗的年龄:'))# like_person_age = 0# 检查用户输入的是否是负数# if dog_age < 0 :# print('你的输入不合法!')# # 如果狗的年龄在两岁以下(包含两岁)# elif dog_age <= 2 :# # 直接将当前的年龄乘以10.5# like_person_age = dog_age * 10.5# # 如果狗的年龄在两岁以上# else :# # 计算前两岁相当于人类的年纪# like_person_age = 2 * 10.5# # 计算超过两岁的部分相对于人类的年纪,并进行相加# like_person_age += ( dog_age - 2 ) * 4# if dog_age > 0 :# print(dog_age,'岁的狗,年纪相当于',like_person_age,'岁的人')## 在if也可以去嵌套if,代码块是可以嵌套的,每增加一个缩进的级别,代码块就低一级# 检查用户的输入是否合法# if dog_age > 0 :# # 如果狗的年龄在两岁以下(包含两岁)# if dog_age <= 2 :# # 直接将当前的年龄乘以10.5# like_person_age = dog_age * 10.5# # 如果狗的年龄在两岁以上# else :# # 计算前两岁相当于人类的年纪# like_person_age = 2 * 10.5# # 计算超过两岁的部分相对于人类的年纪,并进行相加# like_person_age += ( dog_age - 2 ) * 4# print(dog_age,'岁的狗,年纪相当于',like_person_age,'岁的人')# else :# print('请输入一个合法的年龄!')
练习4:
从键盘输入小明的期末成绩:<br /> 当成绩为100时,'奖励一辆BMW'<br /> 当成绩为[80-99]时,'奖励一台iphone'<br /> 当成绩为[60-79]时,'奖励一本参考书'<br /> 其他时,什么奖励也没有
final_result = float(input('请输入期末成绩:'))print('你的期末成绩是:',final_result)if final_result == 100 :print('奖励一辆BMW')elif final_result >= 80 and final_result<=99 :print('奖励一台iphone')elif final_result >= 60 and final_result <= 79 :print('奖励一本参考书')else :print('没有奖励')# 优化结果# 获取小明的成绩# score = float(input('请输入你的期末成绩(0-100):'))# # 打印分割线# print("="*40)# # 检查用户的输入是否合法# if 0 <= score <= 100 :# # 判断发给的奖励# if score == 100 :# print('宝马,拿去玩!')# elif score >= 80 :# print('苹果手机,拿去玩!')# elif score >= 60 :# print('参考书,拿去玩!')# else :# print('棍子一根!')# else :# # 用户输入的不合法,弹出一个友好提示# print('你输入的内容不合法,拉出去毙了!')
练习5:
大家都知道,男大当婚,女大当嫁。那么女方家长要嫁女儿,当然要提出一定的条件:<br /> 高:180cm以上; 富:1000万以上; 帅:500以上;<br /> 如果这三个条件同时满足,则:'我一定要嫁给他'<br /> 如果三个条件有为真的情况,则:'嫁吧,比上不足,比下有余。'<br /> 如果三个条件都不满足,则:'不嫁!'
height = float(input('请输入身高(0-300)c:'))wealth = float(input('请输入财富xxx万元:'))face= float(input('请输入颜值(0-800)cm:'))if height > 180 and wealth > 1000 and face > 500:print('我一定要嫁给他')elif height > 180 or wealth >1000 or height > 180 :print('嫁吧,比上不足,比下有余。')else:print('不嫁!')
循环语句
循环语句可以使指定的代码块重复指定的次数
循环语句分成两种,while循环 和 for循环
while循环
# while循环# 语法:# while 条件表达式 :# 代码块# else :# 代码块# 执行流程:# while语句在执行时,会先对while后的条件表达式进行求值判断,# 如果判断结果为True,则执行循环体(代码块),# 循环体执行完毕,继续对条件表达式进行求值判断,以此类推,# 直到判断结果为False,则循环终止,如果循环有对应的else,则执行else后的代码块# 条件表达式恒为True的循环语句,称为死循环,它会一直运行,慎用!# while True :# print('hello')# 循环的三个要件(表达式)# 初始化表达式,通过初始化表达式初始化一个变量# i = 0# # 条件表达式,条件表达式用来设置循环执行的条件# while i < 10 :# print(i)# # 更新表达式,修改初始化变量的值# i += 1# 创建一个执行十次的循环i = 0while i < 10 :i += 1print(i,'hello')else :print('else中的代码块')
break \ continue \ pass
break:
可以用来立即退出循环语句(包括else)
continue:
可以用来跳过当次循环
break和continue都是只对离他最近的循环起作用
pass:
是用来在判断或循环语句中占位的
例子:# 创建一个5次的循环i = 0while i < 5:if i == 3:breakprint(i)i += 1else :print('循环结束')# i = 0# while i < 5:# i += 1# if i == 2:# continue# print(i)# else :# print('循环结束')i = 0if i < 5:pass
练习
练习1:求100以内所有的奇数之和
求100以内所有的奇数之和
# 求100以内所有的奇数之和result = 0i = 0while i <= 100 :i += 1if i % 2 == 1 :result = result + iprint("100以内所有奇数和为:",result)#优化# 获取所有100以内数# i = 0# # 创建一个变量,用来保存结果# result = 0# while i < 100 :# i += 1# # 判断i是否是奇数# if i % 2 != 0:# result += i# print('result =',result)
练习2: 求100以内所有7的倍数之和,以及个数
求100以内所有7的倍数之和,以及个数
# 求100以内所有7的倍数之和,以及个数result = 0i = 7count = 0while i < 100:count += 1i += 7result = result + iprint('result=',result)print('j=',count)#优化结果# 求100以内所有7的倍数之和,以及个数# i = 7# 创建一个变量,来保存结果# result = 0# 创建一个计数器,用来记录循环执行的次数# 计数器就是一个变量,专门用来记录次数的变量# count = 0# while i < 100:# 为计数器加1# count += 1# result += i# i += 7# print('总和为:',result,'总数量为:',count)
练习3:求1000以内所有的水仙花数
水仙花数是指一个 n 位数(n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身(例如:1**3 + 5**3 + 3**3 = 153)。<br /> 求1000以内所有的水仙花数
# 获取1000以内的三位数i = 100while i < 1000:# 假设,i的百位数是a,十位数b,个位数c# 求i的百位数a = i // 100# 求i的十位数# b = i // 10 % 10b = (i - a * 100) // 10# 求i的个位数字c = i % 10# print(i , a , b , c)# 判断i是否是水仙花数if a**3 + b**3 + c**3 == i :print(i)i += 1
练习4:判断是否是质数
获取用户输入的任意数,判断其是否是质数。质数是只能被1和它自身整除的数,1不是质数也不是合数。
# 获取用户输入的任意数,判断其是否是质数。num = int(input('输入一个任意的大于1的整数:'))# 判断num是否是质数,只能被1和它自身整除的数就是质数# 获取到所有的可能整除num的整数i = 2# 创建一个变量,用来记录num是否是质数,默认认为num是质数flag = Truewhile i < num:# 判断num能否被i整除# 如果num能被i整除,则说明num一定不是质if num % i == 0 :# 一旦进入判断,则证明num不是质数,则需要将flag修改为falseflag = Falsei += 1if flag :print(num,'是质数')else :print(num,'不是质数')
循环嵌套
# 在控制台中打印如下图形# *****# *****# *****# *****# *****## 创建一个循环来控制图形的高度# 循环嵌套时,外层循环没执行一次,内存循环就要执行一圈# i = 0# while i < 5:# # 创建一个内层循环来控制图形的宽度# j = 0# while j < 5:# print("* ",end='')# j += 1# print()# i += 1## * j<1 i=0# ** j<2 i=1# *** j<3 i=2# **** j<4 i=3# ***** j<5 i=4## *****# ****# ***# **# *i = 0while i < 5:j = 0while j < i + 1:print("* ",end='')#这里的end=''是为了使print输出内容不换行j += 1print()i += 1
练习
练习1: 打印99乘法表
打印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
# 创建一个外层循环来控制图形的高度i = 0while i < 9:i += 1# 创建一个内层循环来控制图形的宽度j = 0while j < i:j += 1print(f"{j}*{i}={i*j} ",end="")print()
练习2:求100以内所有的质数
求100以内所有的质数
# 求100以内所有的质数# 创建一个循环,求1-100以内所有的数i = 2while i <= 100:# 创建一个变量,记录i的状态,默认认为i是质数flag = True# 判断i是否是质数# 获取所有可能成为i的因数的数j = 2while j < i:# 判断i能否被j整除if i % j == 0:# i能被j整除,证明i不是质数,修改flag为Falseflag = Falsej += 1# 验证结果并输出if flag :print(i)i += 1
练习优化示例:模块的引入
模块,通过模块可以对Python进行扩展
引入一个time模块,来统计程序执行的时间。time()函数可以用来获取当前的时间,返回的单位是秒
优化前:
求100000以内所有的质数
from time import *begin = time()i = 2while i <= 10000:flag = Truej = 2while j < i:if i % j == 0:flag = Falsej += 1if flag :#print(i)i += 1end = time()print("程序执行花费了:",end - begin , "秒")
结果:程序执行花费了: 8.352874279022217 秒
第一次优化:
from time import *# 获取程序开始的时间begin = time()i = 2while i <= 10000:flag = Truej = 2while j < i:if i % j == 0:flag = False# 一旦进入判断,则证明i一定不是质数,此时内层循环没有继续执行的必要# 使用break来退出内层的循环breakj += 1if flag :# print(i)passi += 1# 获取程序结束的时间end = time()# 计算程序执行的时间print("程序执行花费了:",end - begin , "秒")
结果:程序执行花费了: 0.9832208156585693 秒
第二次优化:
算法优化:一个数的因数最大是其本身的算术平方根
from time import *begin = time()i = 2while i <= 10000:flag = Truej = 2while j <= i ** 0.5:#这里进行优化if i % j == 0:flag = Falsebreakj += 1if flag :# print(i)passi += 1end = time()print("程序执行花费了:",end - begin , "秒")
结果: 程序执行花费了: 0.040992021560668945 秒
可见优化程序对提高程序运行效率十分重要。
总练习 小游戏
小游戏 《唐僧大战白骨精》
内容:
1、身份选择① 显示提示信息欢迎光临 xxx 游戏!请选择你的身份:1.xxx2.xxx请选择:x② 根据用户选择来分配身份(显示不同的提示消息)1.---2.---3.---2、游戏进行① 显示玩家的基本信息(攻击力 生命值)② 显示玩家可以进行的操作:1、练级- 提升玩家的攻击力和生命值2、打BOSS- 玩家对BOSS进行攻击,玩家要攻击BOSS,BOSS对玩家进行反击- 计算BOSS是否被玩家消灭,玩家是否被BOSS消灭- 游戏结束3、逃跑- 退出游戏,显示提示信息,游戏结束!
代码:
# 显示欢迎信息print('-'*20,'欢迎光临《唐僧大战白骨精》','-'*20)# 显示身份选择的信息print('请选择你的身份:')print('\t1.唐僧')print('\t2.白骨精')# 游戏的身份选择player_choose = input('请选择[1-2]:')# 打印一条分割线print('-'*66)# 根据用户的选择来显示不同的提示信息if player_choose == '1':# 选择1print('你已经选择了1,你将以->唐僧<-的身份来进行游戏!')elif player_choose == '2':# 选择2print('你竟然选择了白骨精,太不要脸了,你将以->唐僧<-的身份来进行游戏!')else :# 选择3print('你的输入有误,系统将自动分配身份,你将以->唐僧<-的身份来进行游戏!')# 进入游戏# 创建变量,来保存玩家的生命值和攻击力player_life = 2 # 生命值player_attack = 2 # 攻击力# 创建一个变量,保存boss的生命值和攻击力boss_life = 10boss_attack = 10# 打印一条分割线print('-'*66)# 显示玩家的信息(攻击力、生命值)print(f'唐僧,你的生命值是 {player_life} , 你的攻击力是 {player_attack}')# 由于游戏选项是需要反复显示的,所以必须将其编写到一个循环中while True :# 打印一条分割线print('-'*66)# 显示游戏选项,游戏正式开始print('请选择你要进行的操作:')print('\t1.练级')print('\t2.打BOSS')print('\t3.逃跑')game_choose = input('请选择要做的操作[1-3]:')# 处理用户的选择if game_choose == '1' :# 增加玩家的生命值和攻击力player_life += 2player_attack += 2# 显示最新的信息# 打印一条分割线print('-'*66)# 显示玩家的信息(攻击力、生命值)print(f'恭喜你升级了!,你现在的生命值是 {player_life} , 你的攻击力是 {player_attack}')elif game_choose == '2' :# 玩家攻击boss# 减去boss的生命值,减去的生命值应该等于玩家的攻击力boss_life -= player_attack# 打印一条分割线print('-'*66)print('->唐僧<- 攻击了 ->白骨精<-')# 检查boss是否死亡if boss_life <= 0 :# boss死亡,player胜利,游戏结束print(f'->白骨精<-受到了 {player_attack} 点伤害,重伤不治死了,->唐僧<-赢得了胜利!')# 游戏结束break# boss要反击玩家# 减去玩家的生命值player_life -= boss_attackprint(' ->白骨精<- 攻击了 ->唐僧<-')# 检查玩家是否死亡if player_life <= 0 :# 玩家死亡print(f'你受到了 {boss_attack} 点伤害,重伤不治死了!GAME OVER')# 游戏结束breakelif game_choose == '3' :# 打印一条分割线print('-'*66)# 逃跑,退出游戏print('->唐僧<-一扭头,撒腿就跑!GAME OVER')breakelse :# 打印一条分割线print('-'*66)print('你的输入有误,请重新输入!')
第四部分 序列
列表(list)
列表是Python中的一个对象
对象(object)就是内存中专门用来存储数据的一块区域,之前我们学习的对象,像数值,它只能保存一个单一的数据
列表中可以保存多个有序的数据,列表是用来存储对象的对象
列表的使用:
1.列表的创建
2.操作列表中的数据
列表的介绍
类似于C中的数组,但是更灵活
# 创建列表,通过[]来创建列表my_list = [] # 创建了一个空列表# print(my_list , type(my_list))# 列表存储的数据,我们称为元素# 一个列表中可以存储多个元素,也可以在创建列表时,来指定列表中的元素my_list = [10] # 创建一个只包含一个元素的列表# 当向列表中添加多个元素时,多个元素之间使用,隔开my_list = [10,20,30,40,50] # 创建了一个包含有5个元素的列表# 列表中可以保存任意的对象my_list = [10,'hello',True,None,[1,2,3],print]# 列表中的对象都会按照插入的顺序存储到列表中,# 第一个插入的对象保存到第一个位置,第二个保存到第二个位置# 我们可以通过索引(index)来获取列表中的元素# 索引是元素在列表中的位置,列表中的每一个元素都有一个索引# 索引是从0开始的整数,列表第一个位置索引为0,第二个位置索引为1,第三个位置索引为2,以此类推my_list = [10,20,30,40,50]# 通过索引获取列表中的元素# 语法:my_list[索引] my_list[0]print(my_list[4])# 如果使用的索引超过了最大的范围,会抛出异常print(my_list[5]) IndexError: list index out of range# 获取列表的长度,列表中元素的个数# len()函数,通过该函数可以获取列表的长度# 获取到的长度的值,是列表的最大索引 + 1print(len(my_list)) # 5
列表的切片
切片指从现有列表中,获取一个子列表
# 创建一个列表,一般创建列表时,变量的名字会使用复数stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']# 列表的索引可以是负数# 如果索引是负数,则从后向前获取元素,-1表示倒数第一个,-2表示倒数第二个 以此类推print(stus[-2])# 通过切片来获取指定的元素# 语法:列表[起始:结束]# 通过切片获取元素时,会包括起始位置的元素,不会包括结束位置的元素# 做切片操作时,总会返回一个新的列表,不会影响原来的列表# 起始和结束位置的索引都可以省略不写# 如果省略结束位置,则会一直截取到最后# 如果省略起始位置,则会从第一个元素开始截取# 如果起始位置和结束位置全部省略,则相当于创建了一个列表的副本print(stus[1:])print(stus[:3])print(stus[:])#相当于创建副本print(stus)# 语法:列表[起始:结束:步长]# 步长表示,每次获取元素的间隔,默认值是1print(stus[0:5:3])# 步长不能是0,但是可以是负数print(stus[::0]) ValueError: slice step cannot be zero# 如果是负数,则会从列表的后部向前边取元素print(stus[::-1])
列表的通用操作
# + 和 *# +可以将两个列表拼接为一个列表my_list = [1,2,3] + [4,5,6]# * 可以将列表重复指定的次数my_list = [1,2,3] * 5# print(my_list)# 创建一个列表stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精','沙和尚','沙和尚']# in 和 not in# in用来检查指定元素是否存在于列表中# 如果存在,返回True,否则返回False# not in用来检查指定元素是否不在列表中# 如果不在,返回True,否则返回False# print('牛魔王' not in stus)# print('牛魔王' in stus)# len()获取列表中的元素的个数# min() 获取列表中的最小值# max() 获取列表中的最大值arr = [10,1,2,5,100,77]# print(min(arr) , max(arr))# 两个方法(method),方法和函数基本上是一样,只不过方法必须通过 对象.方法() 的形式调用# xxx.print() 方法实际上就是和对象关系紧密的函数# s.index() 获取指定元素在列表中的第一次出现时的索引(的位置)# print(stus.index('沙和尚'))# index()的第二个参数,表示查找的起始位置 , 第三个参数,表示查找的结束位置# print(stus.index('沙和尚',3,7))# 如果要获取列表中没有的元素,会抛出异常# print(stus.index('牛魔王')) ValueError: '牛魔王' is not in list# s.count() 统计指定元素在列表中出现的次数print(stus.count('牛魔王'))
序列(sequence)
序列是Python中最基本的一种数据结构 (就是一种顺序表)
数据结构指计算机中数据存储的方式
序列用于保存一组有序的数据,所有的数据在序列当中都有一个唯一的位置(索引), 并且序列中的数据会按照添加的顺序来分配索引
序列的分类:
可变序列(序列中的元素可以改变):
列表(list)
不可变序列(序列中的元素不能改变):
字符串(str)
元组(tuple)
前面部分所写的所有操作都是序列的通用操作,是列表,字符串,元组三个文件中的操作
列表的修改
# 创建一个列表stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']# print("修改前:",stus)# 修改列表中的元素# 直接通过索引来修改元素stus[0] = 'sunwukong'stus[2] = '哈哈'# 通过del来删除元素del stus[2] # 删除索引为2的元素stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']# 通过切片来修改列表# 在给切片进行赋值时,只能使用序列(等号两边都是序列)# stus[0:2] = ['牛魔王','红孩儿'] 使用新的元素替换旧元素# stus[0:2] = ['牛魔王','红孩儿','二郎神']# stus[0:0] = ['牛魔王'] # 向索引为0的位置插入元素# 当设置了步长时,序列中元素的个数必须和切片中元素的个数一致# stus[::2] = ['牛魔王','红孩儿','二郎神']# 通过切片来删除元素# del stus[0:2]# del stus[::2]# stus[1:3] = []# 以上操作,只适用于可变序列s = 'hello'# s[1] = 'a' 不可变序列,无法通过索引来修改# 可以通过 list() 函数将其他的序列转换为lists = list(s)print(s)
列表的方法(通过方法修改列表)
# 列表的方法stus = ['孙悟空','猪八戒','沙和尚','唐僧']# print('原列表:',stus)# append()# 向列表的最后添加一个元素stus.append('唐僧')# insert()# 向列表的指定位置插入一个元素# 参数:# 1.要插入的位置# 2.要插入的元素stus.insert(2,'唐僧')# extend()# 使用新的序列来扩展当前序列# 需要一个序列作为参数,它会将该序列中的元素添加到当前列表中stus.extend(['唐僧','白骨精'])stus += ['唐僧','白骨精']#这两者的效果是一模一样的# clear()# 清空序列stus.clear()# pop()# 根据索引删除并返回被删除的元素result = stus.pop(2) # 删除索引为2的元素result = stus.pop() # 删除最后一个print('result =',result)# remove()# 删除指定值的元素,如果相同值得元素有多个,只会删除第一个stus.remove('猪八戒')# reverse()# 用来反转列表stus.reverse()# sort()# 用来对列表中的元素进行排序,默认是升序排列# 如果需要降序排列,则需要传递一个reverse=True作为参数my_list = list('asnbdnbasdabd')#这里是类型转换,将字符串转换为列表(字母按字母顺序进行排列)my_list = [10,1,20,3,4,5,0,-2]print('修改前',my_list)my_list.sort(reverse=True)#降序排列print('修改后',my_list)# print('修改后:',stus)
range()函数
range()是一个函数,可以用来生成一个自然数的序列
# range()是一个函数,可以用来生成一个自然数的序列r = range(5) # 生成一个这样的序列[0,1,2,3,4]r = range(0,10,2)r = range(10,0,-1)# 该函数需要三个参数# 1.起始位置(可以省略,默认是0)# 2.结束位置# 3.步长(可以省略,默认是1)print(list(r))# 通过range()可以创建一个执行指定次数的for循环# for()循环除了创建方式以外,其余的都和while一样,# 包括else、包括break continue都可以在for循环中使用# 并且for循环使用也更加简单for i in range(30):print(i)#也可以遍历字符串for s in 'hello':print(s)
列表的遍历
遍历列表,指的就是将列表中的所有元素取出来
遍历列表(通过索引遍历)
# 创建列表stus = ['孙悟空','猪八戒','沙和尚','唐僧','白骨精','蜘蛛精']# 遍历列表(通过索引遍历)# print(stus[0])# print(stus[1])# print(stus[2])# print(stus[3])
通过while循环来遍历列表
# 通过while循环来遍历列表# i = 0# while i < len(stus):# print(stus[i])# i += 1
通过for循环来遍历列表
# 通过for循环来遍历列表# 语法:# for 变量 in 序列 :# 代码块# for循环的代码块会执行多次,序列中有几个元素就会执行几次# 没执行一次就会将序列中的一个元素赋值给变量,# 所以我们可以通过变量,来获取列表中的元素for s in stus :print(s)
EMS 练习
Employee Manager System 员工管理系统
代码需求:
- 做命令行版本的员工管理系统- 功能:四个:1.查询- 显示当前系统当中的所有员工2.添加- 将员工添加到当前系统中3.删除- 将员工从系统当中删除4.退出- 退出系统- 员工信息要保存到哪里? 列表,在系统中应该有一个列表,专门用来保存所有员工信息的
代码实现:
# 显示系统的欢迎信息print('-'*20 , '欢迎使用员工管理系统', '-'*20)# 创建一个列表,用来保存员工的信息,员工的信息以字符串的形式统一保存到列表emps = ['孙悟空\t18\t男\t花果山','猪八戒\t28\t男\t高老庄']# 创建一个死循环while True:# 显示用户的选项print('请选择要做的操作:')print('\t1.查询员工')print('\t2.添加员工')print('\t3.删除员工')print('\t4.退出系统')user_choose = input('请选择[1-4]:')print('-'*62)# 根据用户的选择做相关的操作if user_choose == '1' :# 查询员工# 打印表头print('\t序号\t姓名\t年龄\t性别\t住址')# 创建一个变量,来表示员工的序号n = 1# 显示员工信息for emp in emps :print(f'\t{n}\t{emp}')n += 1elif user_choose == '2':# 添加员工# 获取要添加员工的信息,姓名、年龄、性别、住址emp_name = input('请输入员工的姓名:')emp_age = input('请输入员工的年龄:')emp_gender = input('请输入员工的性别:')emp_address = input('请输入员工的住址:')# 创建员工信息# 将四个信息拼接为一个字符串,然后插入到列表中emp = f'{emp_name}\t{emp_age}\t{emp_gender}\t{emp_address}'# 显示一个提示信息print('以下员工将被添加到系统中')print('-'*62)print('姓名\t年龄\t性别\t住址')print(emp)print('-'*62)user_confirm = input('是否确认该操作[Y/N]:')# 判断if user_confirm == 'y' or user_confirm == 'yes' :# 确认emps.append(emp)# 显示提示信息print('添加成功!')else :# 取消操作print('添加已取消!')elif user_choose == '3':# 删除员工,根据员工的序号来删除员工# 获取要删除的员工的序号del_num = int(input('请输入要删除的员工的序号:'))# 判断序号是否有效if 0 < del_num <= len(emps) :# 输入合法,根据序号来获取索引del_i = del_num - 1# 显示一个提示信息print('以下员工将被删除')print('-'*62)print('\t序号\t姓名\t年龄\t性别\t住址')print(f'\t{del_num}\t{emps[del_i]}')print('-'*62)user_confirm = input('该操作不可恢复,是否确认[Y/N]:')# 判断if user_confirm == 'y' or user_confirm == 'yes' :# 删除元素emps.pop(del_i)# 显示提示print('员工已被删除!')else :# 操作取消print('操作已取消!')else :# 输入有误print('您的输入有误,请重新操作!')elif user_choose == '4':# 退出print('欢迎使用!再见!')input('点击回车键退出!')breakelse :print('您的输入有误,请重新选择!')# 打印分割线print('-'*62)
元组
元组 tuple(除了不可变,剩下的和序列差不多)
元组是一个不可变的序列,它的操作的方式基本上和列表是一致的,所以你在操作元组时,就把元组当成是一个不可变的列表就ok了
一般当我们希望数据不改变时,就使用元组,其余情况都使用列表.
创建元组:
# 创建元组# 使用()来创建元组my_tuple = () # 创建了一个空元组# print(my_tuple,type(my_tuple)) # <class 'tuple'>my_tuple = (1,2,3,4,5) # 创建了一个5个元素的元组# 元组是不可变对象,不能尝试为元组中的元素重新赋值# my_tuple[3] = 10 TypeError: 'tuple' object does not support item assignment# print(my_tuple[3])# 当元组不是空元组时,括号可以省略# 如果元组不是空元组,它里边至少要有一个,(逗号)my_tuple = 10,20,30,40my_tuple = 40,# print(my_tuple , type(my_tuple))my_tuple = 10 , 20 , 30 , 40
元组的解包(解构)
# 解包指就是将元组当中每一个元素都赋值给一个变量a,b,c,d = my_tuple# print("a =",a)# print("b =",b)# print("c =",c)# print("d =",d)a = 100b = 300# print(a , b)# 交互a 和 b的值,这时我们就可以利用元组的解包(把后面的部分看作一个元组)a , b = b , a# print(a , b)my_tuple = 10 , 20 , 30 , 40# 在对一个元组进行解包时,变量的数量必须和元组中的元素的数量一致# 也可以在变量前边添加一个*,这样变量将会获取元组中所有剩余的元素a , b , *c = my_tuplea , *b , c = my_tuple*a , b , c = my_tuplea , b , *c = [1,2,3,4,5,6,7]a , b , *c = 'hello world'# 不能同时出现两个或以上的*变量# *a , *b , c = my_tuple SyntaxError: two starred expressions in assignmentprint('a =',a)print('b =',b)print('c =',c)上面三行的输出:a = hb = ec = ['l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
可变对象
- 每个对象中都保存了三个数据:id(标识)type(类型)value(值)- 列表就是一个可变对象a = [1,2,3]- a[0] = 10 (改对象)(像指针一样)- 这个操作是在通过变量去修改对象的值- 这种操作不会改变变量所指向的对象- 当我们去修改对象时,如果有其他变量也指向了该对象,则修改也会在其他的变量中体现- a = [4,5,6] (改变量)- 这个操作是在给变量重新赋值- 这种操作会改变变量所指向的对象- 为一个变量重新赋值时,不会影响其他的变量- 一般只有在为变量赋值时才是修改变量,其余的都是修改对象
== != is is not的区别
== != 比较的是对象的值是否相等
is is not 比较的是对象的id是否相等(比较两个对象是否是同一个对象)
a = [1,2,3]b = [1,2,3]print(a,b)print(id(a),id(b))print(a == b) # a和b的值相等,使用==会返回Trueprint(a is b) # a和b不是同一个对象,内存地址不同,使用is会返回False
字典(dict)
字典属于一种新的数据结构,称为映射(mapping)
字典的作用和列表类似,都是用来存储对象的容器。列表存储数据的性能很好,但是查询数据的性能的很差。在字典中每一个元素都有一个唯一的名字,通过这个唯一的名字可以快速的查找到指定的元素。
在查询元素时,字典的效率是非常快的
在字典中可以保存多个对象,每个对象都会有一个唯一的名字
1. 这个唯一的名字,我们称其为键(key),通过key可以快速的查询value2. 这个对象,我们称其为值(value)3. 所以字典,我们也称为叫做键值对(key-value)结构4. 每个字典中都可以有多个键值对,而每一个键值对我们称其为一项(item)
# 使用 {} 来创建字典d = {} # 创建了一个空字典# 创建一个包含有数据的字典# 语法:# {key:value,key:value,key:value}# 字典的值可以是任意对象# 字典的键可以是任意的不可变对象(int、str、bool、tuple ...),但是一般我们都会使用str# 字典的键是不能重复的,如果出现重复的后边的会替换到前边的# d = {'name':'孙悟空' , 'age':18 , 'gender':'男' , 'name':'sunwukong'}d = {'name':'孙悟空' ,'age':18 ,'gender':'男' ,'name':'sunwukong'}# print(d , type(d))# 需要根据键来获取值print(d['name'],d['age'],d['gender'])# 如果使用了字典中不存在的键,会报错# print(d['hello']) KeyError: 'hello'
字典的使用
创建字典:
# 创建字典# 使用{}# 语法:{k1:v1,k2:v2,k3:v3}# 使用 dict()函数来创建字典# 每一个参数都是一个键值对,参数名就是键,参数名就是值(这种方式创建的字典,key都是字符串)d = dict(name='孙悟空',age=18,gender='男')# 也可以将一个包含有双值子序列的序列转换为字典# 双值序列,序列中只有两个值,[1,2] ('a',3) 'ab'# 子序列,如果序列中的元素也是序列,那么我们就称这个元素为子序列# [(1,2),(3,5)]d = dict([('name','孙悟空'),('age',18)])# print(d , type(d))d = dict(name='孙悟空',age=18,gender='男')
获取字典中键值对的个数
# len() 获取字典中键值对的个数print(len(d))
检查字典中是否包含指定的键
# in 检查字典中是否包含指定的键# not in 检查字典中是否不包含指定的键print('hello' in d)
获取字典中的值
# 第一种,根据键来获取值# 语法:d[key]print(d['age'])#要加引号n = 'name' #要加引号print(d[n])# 第二种,通过[]来获取值时,如果键不存在,会抛出异常 KeyError# get(key[, default]) 该方法用来根据键来获取字典中的值# 如果获取的键在字典中不存在,会返回None# 也可以指定一个默认值,来作为第二个参数,这样获取不到值时将会返回默认值print(d.get('name'))print(d.get('hello','默认值'))
修改字典 添加键值对
# 修改字典# d[key] = value 如果key存在则覆盖,不存在则添加d['name'] = 'sunwukong' # 修改字典的key-valued['address'] = '花果山' # 向字典中添加key-value# setdefault(key[, default]) 方法可以用来向字典中添加key-value# 如果key已经存在于字典中,则返回key的值,不会对字典做任何操作# 如果key不存在,则向字典中添加这个key,并设置valueresult = d.setdefault('name','猪八戒')result = d.setdefault('hello','猪八戒')# update([other])# 将其他的字典中的key-value添加到当前字典中# 如果有重复的key,则后边的会替换到当前的d = {'a':1,'b':2,'c':3}d2 = {'d':4,'e':5,'f':6, 'a':7}d.update(d2)
修改字典 删除键值对
# 删除,可以使用 del 来删除字典中的 key-valued = {'a':1,'b':2,'c':3}del d['a']del d['b']# popitem()方法# 随机删除字典中的一个键值对,一般都会删除最后一个键值对# 删除之后,它会将删除的key-value作为返回值返回# 返回的是一个元组,元组中有两个元素,第一个元素是删除的key,第二个是删除的value# 当使用popitem()删除一个空字典时,会抛出异常 KeyError: 'popitem(): dictionary is empty'd.popitem()result = d.popitem()# pop(key[, default])方法# 根据key删除字典中的key-value# 会将被删除的value返回!# 如果删除不存在的key,会抛出异常# 如果指定了默认值,再删除不存在的key时,不会报错,而是直接返回默认值result = d.pop('d')result = d.pop('z','这是默认值')# clear()用来清空字典d.clear()
修改字典 浅复制
copy()# 该方法用于对字典进行浅复制# 复制以后的对象,和原对象是独立,修改一个不会影响另一个# 注意,浅复制会简单复制对象内部的值,如果值也是一个可变对象,这个可变对象不会被复制d = {'a':1,'b':2,'c':3}d2 = d.copy()# d['a'] = 100
例子:(没太理解——2022.4.11)
例子:d = {'a':{'name':'孙悟空','age':18},'b':2,'c':3}d2 = d.copy()d2['a']['name'] = '猪八戒'print('d = ',d , id(d))print('d2 = ',d2 , id(d2))运行结果:d = {'a': {'name': '猪八戒', 'age': 18}, 'b': 2, 'c': 3} 2080115470648d2 = {'a': {'name': '猪八戒', 'age': 18}, 'b': 2, 'c': 3} 2080115471128
修改字典 遍历字典
# 遍历字典(三个方法)# keys() 该方法会返回字典的所有的key# 该方法会返回一个序列,序列中保存有字典的所有的键d = {'name':'孙悟空','age':18,'gender':'男'}# 通过遍历keys()来获取所有的键for k in d.keys() :print(k , d[k])# values()# 该方法会返回一个序列,序列中保存有字典的左右的值for v in d.values():print(v)# items()# 该方法会返回字典中所有的项# 它会返回一个序列,序列中包含有双值子序列# 双值分别是,字典中的key和value 然后进行元组的解包print(d.items())for k,v in d.items() :print(k , '=' , v)
集合(set)
集合和列表非常相似
不同点:
- 集合中只能存储不可变对象
- 合中存储的对象是无序(不是按照元素的插入顺序保存)不能通过索引操作集合
- 集合中不能出现重复的元素
创建集合
# 使用 {} 来创建集合s = {10,3,5,1,2,1,2,3,1,1,1,1} # <class 'set'># s = {[1,2,3],[4,6,7]} TypeError: unhashable type: 'list'#不能储存可变对象# 使用 set() 函数来创建集合s = set() # 空集合# 可以通过set()来将序列和字典转换为集合s = set([1,2,3,4,5,1,1,2,3,4,5])s = set('hello')s = set({'a':1,'b':2,'c':3}) # 使用set()将字典转换为集合时,只会包含字典中的键
集合的操作
# 创建集合s = {'a' , 'b' , 1 , 2 , 3 , 1}# 使用in和not in来检查集合中的元素# print('c' in s)# 使用len()来获取集合中元素的数量# print(len(s))# add() 向集合中添加元素s.add(10)s.add(30)# update() 将一个集合中的元素添加到当前集合中# update()可以传递序列或字典作为参数,字典只会使用键s2 = set('hello')s.update(s2)s.update((10,20,30,40,50))s.update({10:'ab',20:'bc',100:'cd',1000:'ef'})# {1, 2, 3, 100, 40, 'o', 10, 1000, 'a', 'h', 'b', 'l', 20, 50, 'e', 30}# pop()随机删除并返回一个集合中的元素# result = s.pop()# remove()删除集合中的指定元素s.remove(100)s.remove(1000)# clear()清空集合s.clear()# copy()对集合进行浅复制s2 = s.copy()
集合的运算
# 在对集合做运算时,不会影响原来的集合,而是返回一个运算结果# 创建两个集合s = {1,2,3,4,5}s2 = {3,4,5,6,7}# & 交集运算result = s & s2 # {3, 4, 5}# | 并集运算result = s | s2 # {1,2,3,4,5,6,7}# - 差集result = s - s2 # {1, 2}# ^ 异或集 获取只在一个集合中出现的元素result = s ^ s2 # {1, 2, 6, 7}# <= 检查一个集合是否是另一个集合的子集# 如果a集合中的元素全部都在b集合中出现,那么a集合就是b集合的子集,b集合是a集合超集a = {1,2,3}b = {1,2,3,4,5}result = a <= b # Trueresult = {1,2,3} <= {1,2,3} # Trueresult = {1,2,3,4,5} <= {1,2,3} # False# < 检查一个集合是否是另一个集合的真子集# 如果超集b中含有子集a中所有元素,并且b中还有a中没有的元素,则b就是a的真超集,a是b的真子集result = {1,2,3} < {1,2,3} # Falseresult = {1,2,3} < {1,2,3,4,5} # True# >= 检查一个集合是否是另一个的超集# > 检查一个集合是否是另一个的真超集print('result =',result)
第五部分 函数
函数简介(function)
- 函数也是一个对象- 对象是内存中专门用来存储数据的一块区域- 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用- 创建函数:def 函数名([形参1,形参2,...形参n]) :代码块- 函数名必须要符号标识符的规范(可以包含字母、数字、下划线、但是不能以数字开头)- 函数中保存的代码不会立即执行,需要调用函数代码才会执行- 调用函数:函数对象()- 定义函数一般都是要实现某种功能的
定义函数
# 比如有如下三行代码,这三行代码是一个完整的功能# print('Hello')# print('你好')# print('再见')# 定义一个函数def fn() :print('这是我的第一个函数!')print('hello')print('今天天气真不错!')# 打印fn# print(fn) <function fn at 0x03D2B618># print(type(fn)) <class 'function'># fn是函数对象 fn()调用函数# print是函数对象 print()调用函数# fn()# 调用fn函数# 定义一个函数,可以用来求任意两个数的和def sum() :a = 123b = 456print(a + b)# 定义函数时指定形参def fn2(a , b) :# print('a =',a)# print('b =',b)print(a,"+",b,"=",a + b)# 调用函数时,来传递实参fn2(10,20)fn2(123,456)
函数的参数
- 在定义函数时,可以在函数名后的()中定义数量不等的形参,多个形参之间使用,隔开- 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值- 实参(实际参数)- 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参,实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参
练习1:定义一个函数,可以用来求任意三个数的乘积
# 求任意三个数的乘积def mul(a,b,c):print(a*b*c)
练习1:定义一个函数,可以根据不同的用户名显示不同的欢迎信息
# 根据不同的用户名显示不同的欢迎信息def welcome(username):print('欢迎',username,'光临')# mul(1,2,3)# welcome('孙悟空')
参数传递实例:
# 定义一个函数# 定义形参时,可以为形参指定默认值# 指定了默认值以后,如果用户传递了参数则默认值没有任何作用# 如果用户没有传递,则默认值就会生效def fn(a = 5 , b = 10 , c = 20):print('a =',a)print('b =',b)print('c =',c)# fn(1 , 2 , 3)# fn(1 , 2)# fn()# 实参的传递方式# 位置参数# 位置参数就是将对应位置的实参复制给对应位置的形参# 第一个实参赋值给第一个形参,第二个实参赋值给第二个形参 。。。# fn(1 , 2 , 3)# 关键字参数# 关键字参数,可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数# fn(b=1 , c=2 , a=3)# print('hello' , end='')# 位置参数和关键字参数可以混合使用# 混合使用关键字和位置参数时,必须将位置参数写到前面# fn(1,c=30)def fn2(a):print('a =',a)# 函数在调用时,解析器不会检查实参的类型# 实参可以传递任意类型的对象(和C有所区别)b = 123b = Trueb = 'hello'b = Noneb = [1,2,3]# fn2(b)fn2(fn)# 参数类型任意方便,但也会产生一些问题def fn3(a , b):print(a+b)# fn3(123,"456")def fn4(a):# 在函数中对形参进行重新赋值,不会影响其他的变量# a = 20# a是一个列表,尝试修改列表中的元素# 如果形参执行的是一个对象,当我们通过形参去修改对象时(该对象)# 会影响到所有指向该对象的变量(类似于传地址调用)a[0] = 30print('a =',a,id(a))c = 10c = [1,2,3]fn4(c)# 想要传值调用,不改变实参本身,可以这样# fn4(c.copy())# fn4(c[:])
不定长的参数:
# 不定长的参数# 定义一个函数,可以求任意个数字的和# 在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参def sum(*nums):# 定义一个变量,来保存结果result = 0# 遍历元组,并将元组中的数进行累加for n in nums :result += nprint(result)# sum(123,456,789,10,20,30,40) 想要参数数量随便变化# 在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参# 它将会将所有的实参保存到一个元组中# a,b,*c = (1,2,3,4,5,6)# *a会接受所有的位置实参,并且会将这些实参统一保存到一个元组中(装包)def fn(*a):print("a =",a,type(a))# fn(1,2,3,4,5)# 带星号的形参只能有一个# 带星号的参数,可以和其他参数配合使用# 第一个参数给a,第二个参数给b,剩下的都保存到c的元组中# def fn2(a,b,*c):# print('a =',a)# print('b =',b)# print('c =',c)# 可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递(c就必须使用关键字参数的形式传递)# 第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数# def fn2(a,*b,c):# print('a =',a)# print('b =',b)# print('c =',c)# 所有的位置参数都给a,b和c必须使用关键字参数# def fn2(*a,b,c):# print('a =',a)# print('b =',b)# print('c =',c)# 如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递def fn2(*,a,b,c):print('a =',a)print('b =',b)print('c =',c)# fn2(a=3,b=4,c=5)# *形参只能接收位置参数,而不能接收关键字参数# def fn3(*a) :# print('a =',a)# **形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中# 字典的key就是参数的名字,字典的value就是参数的值# **形参只能有一个,并且必须写在所有参数的最后def fn3(b,c,**a) :print('a =',a,type(a))print('b =',b)print('c =',c)# fn3(b=1,d=2,c=3,e=10,f=20)# 参数的解包(拆包)def fn4(a,b,c):print('a =',a)print('b =',b)print('c =',c)# 创建一个元组t = (10,20,30)# 传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递# 这里要求序列中元素的个数必须和形参的个数的一致# fn4(*t)# 创建一个字典d = {'a':100,'b':200,'c':300}# 通过 **来对一个字典进行解包操作fn4(**d)
函数的返回值:
返回值,返回值就是函数执行以后返回的结果
可以通过 return 来指定函数的返回值
可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值
这是一个没有返回值的函数:
def sum(*nums):# 定义一个变量,来保存结果result = 0# 遍历元组,并将元组中的数进行累加for n in nums :result += nprint(result)# sum(123,456,789)
return 后边跟什么值,函数就会返回什么值
return 后边可以跟任意的对象(字符串,列表,字典),返回值甚至可以是一个函数
这是一个有返回值的函数:
def fn():# return 'Hello'# return [1,2,3]# return {'k':'v'}def fn2() :print('hello')#嵌套函数return fn2 # 返回值也可以是一个函数r = fn() # 这个函数的执行结果就是它的返回值
如果仅仅写一个return 或者 不写return,则相当于return None
在函数中,return后的代码都不会执行,return 一旦执行函数自动结束
return continue break三者的区别:
def fn4() :for i in range(5):if i == 3 :# break 用来退出当前循环# continue 用来跳过当次循环return # return 用来结束函数print(i)print('循环执行完毕!')
fn5 和 fn5()的区别
def fn5():return 10print(fn5)# fn5是函数对象,打印fn5实际是在打印函数对象 <function fn5 at 0x05771BB8>print(fn5())# fn5()是在调用函数,打印fn5()实际上是在打印fn5()函数的返回值 10
文档字符串(函数的描述)
help 函数
help()是Python中的内置函数
通过help()函数可以查询python中的函数的用法
语法:help(函数对象)
help(print) # 获取print()函数的使用说明结果:Help on built-in function print in module builtins:print(...)print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)Prints the values to a stream, or to sys.stdout by default.Optional keyword arguments:file: a file-like object (stream); defaults to the current sys.stdout.sep: string inserted between values, default a space.end: string appended after the last value, default a newline.flush: whether to forcibly flush the stream.
利用函数字符串编写函数说明
# 文档字符串(doc str)# 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明# 当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明# 文档字符串非常简单,其实直接在函数的第一行写一个字符串就是文档字符串def fn(a:int,b:bool,c:str='hello') -> int:#这里等于号后面是对参数类型的描述,后面的箭头表示其返回值的类型'''这是一个文档字符串的示例(尽量使用英文编写)函数的作用:。。。。。函数的参数:a,作用,类型,默认值。。。。b,作用,类型,默认值。。。。c,作用,类型,默认值。。。。'''return 10help(fn)
函数的作用域和命名空间
作用域
作用域(scope)
作用域指的是变量生效的区域
b = 20 # 全局变量def fn():a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问print('函数内部:','a =',a)print('函数内部:','b =',b)fn()print('函数外部:','a =',a)#无法调用print('函数外部:','b =',b)
在Python中一共有两种作用域
全局作用域
- 全局作用域在程序执行时创建,在程序执行结束时销毁
- 所有函数以外的区域都是全局作用域
- 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
函数作用域
- 函数作用域在函数调用时创建,在调用结束时销毁
- 函数每调用一次就会产生一个新的函数作用域
- 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
变量的查找
当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,如果没有则继续去上一级作用域中寻找,如果有则使用,
如果依然没有则继续去上一级作用域中寻找,以此类推。直到找到全局作用域,依然没有找到,则会抛出异常:
NameError: name ‘a’ is not defined
变量修改:
a = 20def fn3():# a = 10 # 在函数中为变量赋值时,默认都是为局部变量赋值# 如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量global a # 声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的aa = 10 # 修改全局变量print('函数内部:','a =',a)
命名空间
命名空间(namespace)
命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
每一个作用域都会有一个它对应的命名空间
全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
命名空间实际上就是一个字典,是一个专门用来存储变量的字典
locals()用来获取当前作用域的命名空间
如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
返回的是一个字典
scope = locals() # 当前命名空间print(type(scope))# print(a)# print(scope['a'])# 向scope中添加一个key-valuescope['c'] = 1000 # 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做)# print(c)
def fn4():a = 10# scope = locals() # 在函数内部调用locals()会获取到函数的命名空间# scope['b'] = 20 # 可以通过scope来操作函数的命名空间,但是也是不建议这么做# globals() 函数可以用来在任意位置获取全局命名空间global_scope = globals()# print(global_scope['a'])global_scope['a'] = 30# print(scope)fn4()
递归
求10的阶乘
基础:
# 尝试求10的阶乘(10!)# 1! = 1# 2! = 1*2 = 2# 3! = 1*2*3 = 6# 4! = 1*2*3*4 = 24# print(1*2*3*4*5*6*7*8*9*10)
函数:
# 创建一个变量保存结果# n = 10# for i in range(1,10):# n *= i# print(n)# 创建一个函数,可以用来求任意数的阶乘def factorial(n):'''该函数用来求任意数的阶乘参数:n 要求阶乘的数字'''# 创建一个变量,来保存结果result = nfor i in range(1,n):result *= ireturn result# 求10的阶乘# print(factorial(20))
递归式的函数:
从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢?
从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的什么故事呢?….
递归简单理解就是自己去引用自己!
递归式函数,在函数中自己调用自己!
# 无穷递归,如果这个函数被调用,程序的内存会溢出,效果类似于死循环def fn():fn()fn()
递归是解决问题的一种方式,它和循环很像
它的整体思想是,将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题
递归式函数的两个要件
1.基线条件
- 问题可以被分解为的最小问题,当满足基线条件时,递归就不在执行了
2.递归条件
- 将问题继续分解的条件
递归和循环类似,基本是可以互相代替的,循环编写起来比较容易,阅读起来稍难,递归编写起来难,但是方便阅读
利用递归求阶乘:
def factorial(n):'''该函数用来求任意数的阶乘参数:n 要求阶乘的数字'''# 基线条件 判断n是否为1,如果为1则此时不能再继续递归if n == 1 :# 1的阶乘就是1,直接返回1return 1# 递归条件return n * factorial(n-1)# print(factorial(10))
递归练习
创建一个函数 power 来为任意数字做幂运算 n ** i
def power(n , i):'''power()用来为任意的数字做幂运算参数:n 要做幂运算的数字i 做幂运算的次数'''# 基线条件if i == 1:# 求1次幂return n# 递归条件return n * power(n , i-1)# print(power(8,6))
创建一个函数,用来检查一个任意的字符串是否是回文字符串
先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串
如果一致,则看剩余的部分是否是回文字符串
# abcdefgfedcba# 先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串# 如果一致,则看剩余的部分是否是回文字符串# 检查 abcdefgfedcba 是不是回文# 检查 bcdefgfedcb 是不是回文# 检查 cdefgfedc 是不是回文# 检查 defgfed 是不是回文# 检查 efgfe 是不是回文# 检查 fgf 是不是回文# 检查 g 是不是回文(基线条件)def hui_wen(s):'''该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False参数:s:就是要检查的字符串'''# 基线条件if len(s) < 2 :# 字符串的长度小于2,则字符串一定是回文return Trueelif s[0] != s[-1]:# 第一个字符和最后一个字符不相等,不是回文字符串return False# 递归条件return hui_wen(s[1:-1])print(hui_wen('abcdefgfedcba'))
高阶函数
函数式编程
在Python中,函数是一等对象
- 一等对象一般都会具有如下特点:
① 对象是在运行时创建的
② 能赋值给变量或作为数据结构中的元素
③ 能作为参数传递
④ 能作为返回值返回
高阶函数
- 高阶函数至少要符合以下两个特点中的一个
① 接收一个或多个函数作为参数
② 将函数作为返回值返回
一个普通的函数:
# 创建一个列表l = [1,2,3,4,5,6,7,8,9,10]# 定义一个函数# 可以将指定列表中的所有的偶数,保存到一个新的列表中返回def fn(lst) :'''fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回参数:lst:要进行筛选的列表'''# 创建一个新列表new_list = []# 对列表进行筛选for n in lst :# 判断n的奇偶if i % 2 == 0 ::new_list.append(n)# 返回新列表return new_list
函数化编程:
检查一个任意的数字是否是偶数
# 定义一个函数,用来检查一个任意的数字是否是偶数def fn2(i) :if i % 2 == 0 :return Truereturn False
这个函数用来检查指定的数字是否大于5
# 这个函数用来检查指定的数字是否大于5def fn3(i):if i > 5 :return Truereturn False
主函数:
def fn(func , lst) :'''fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回参数:lst:要进行筛选的列表'''# 创建一个新列表new_list = []# 对列表进行筛选for n in lst :# 判断n的奇偶if func(n) :new_list.append(n)# if n > 5 :# new_list.append(n)# 返回新列表return new_list
调用时,主函数可以直接选择调用任意函数,和参数 (规则和参数都作为输入)
当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数
print(fn(fn2 , l))#实现的功能也是将指定列表中的所有的偶数,保存到一个新的列表中返回
filter()过滤器
filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中参数:1.函数,根据该函数来过滤序列(可迭代的结构)2.需要过滤的序列(可迭代的结构)返回值:过滤后的新序列(可迭代的结构)
示例:
r=filter(fn4 ,l)#这里fn4作为参数,所以不加()print(list(r))# fn4是作为参数传递进filter()函数中# 而fn4实际上只有一个作用,就是作为filter()的参数# filter()调用完毕以后,fn4就已经没用
匿名函数:
匿名函数 lambda 函数表达式 (语法糖)lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式语法:lambda 参数列表 : 返回值匿名函数一般都是作为参数使用,其他地方一般不会使用
示例:
#普通写法:def fn5(a , b):return a + b#匿名写法:lambda a,b : a + b调用:整体加括号,参数也放进括号里(lambda a,b : a + b)(10,20)#一般不这么用# 也可以将匿名函数赋值给一个变量,一般不会这么做fn6 = lambda a,b : a + b# print(fn6(10,30))
对本节第一个程序的改造:
def fn4(i):return i % 3 == 0#fn4可以有如上的简写#在利用filter()和匿名函数调用就是下面这样:r = filter(lambda i : i > 5 , l)print(list(r))#这两行就起到了本节第一个普通函数fn的效果
map()函数
# map()# map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回l = [1,2,3,4,5,6,7,8,9,10]r = map(lambda i : i ** 2 , l)#求列表每一个元素的2次方# print(list(r))
sort()方法
# sort()# 该方法用来对列表中的元素进行排序# sort()方法默认是直接比较列表中的元素的大小# 在sort()可以接收一个关键字参数 , key# key需要一个函数作为参数,当设置了函数作为参数# 每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小l = ['bb','aaaa','c','ddddddddd','fff']# l.sort(key=len)l = [2,5,'1',3,'6','4']l.sort(key=int)# print(l)
sorted()函数
# sorted()# 这个函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序# 并且使用sorted()排序不会影响原来的对象,而是返回一个新对象l = [2,5,'1',3,'6','4']# l = "123765816742634781"print('排序前:',l)print(sorted(l,key=int))print('排序后:',l)
闭包
将函数作为返回值返回,也是一种高阶函数
这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量
可以将一些私有的数据藏到的闭包中
语法示例:
def fn():a = 10# 函数内部再定义一个函数def inner():print('我是fn2' , a)# 将内部函数 inner作为返回值返回return inner# r是一个函数,是调用fn()后返回的函数# 这个函数实在fn()内部定义,并不是全局函数# 所以这个函数总是能访问到fn()函数内的变量,其他函数访问不了r = fn()r()
示例:求多个数的平均值:
正常写法:
# 求多个数的平均值nums = [50,30,20,10,77]# sum()用来求一个列表中所有元素的和print(sum(nums)/len(nums))
闭包:
# 形成闭包的要件# ① 函数嵌套# ② 将内部函数作为返回值返回# ③ 内部函数必须要使用到外部函数的变量def make_averager():# 创建一个列表,用来保存数值nums = []# 创建一个函数,用来计算平均值def averager(n) :# 将n添加到列表中nums.append(n)# 求平均值return sum(nums)/len(nums)return averageraverager = make_averager()print(averager(10))print(averager(20))print(averager(30))print(averager(40))
装饰器
现在有以下程序:
def add(a , b):'''求任意两个数的和'''r = a + breturn rdef mul(a , b):'''求任意两个数的积'''r = a * breturn rr = add(123,456)print(r)
当前需求:希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕
我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
① 如果要修改的函数过多,修改起来会比较麻烦
② 并且不方便后期的维护
③ 并且这样做会违反开闭原则(OCP)
程序的设计,要求开发对程序的扩展,要关闭对程序的修改
我们希望在不修改原函数的情况下,来对函数进行扩展:
只需要根据现有的函数,来创建一个新的函数:
def fn2():print('函数开始执行~~~')fn()print('函数执行结束~~~')
对add函数进行修改(记得传递参数)
def new_add(a,b):print('计算开始~~~')r = add(a,b)print('计算结束~~~')return r# r = new_add(111,222)# print(r)
上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了
但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了
为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数
def begin_end(old):'''用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束参数:old 要扩展的函数对象'''# 创建一个新函数def new_function(*args , **kwargs):print('开始执行~~~~')# 调用被扩展的函数result = old(*args , **kwargs)print('执行结束~~~~')# 返回函数的执行结果return result# 返回新函数return new_functionf = begin_end(fn)f2 = begin_end(add)f3 = begin_end(mul)# r = f()# r = f2(123,456)# r = f3(123,456)# print(r)
向begin_end()这种函数我们就称它为装饰器
通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
在开发中,我们都是通过装饰器来扩展函数的功能的
在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰
@begin_enddef say_hello():print('大家好~~~')say_hello()
这个就相当于:
f = begin_end(say_hello)
第六部分 对象
什么是对象?
- 对象是内存中专门用来存储数据的一块区域。- 对象中可以存放各种数据(比如:数字、布尔值、代码)- 对象由三部分组成:1.对象的标识(id)2.对象的类型(type)3.对象的值(value)
面向对象(oop)
- Python是一门面向对象的编程语言
- 所谓的面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的
- 面向过程的编程的语言
- 面向过程指将我们的程序的逻辑分解为一个一个的步骤,
通过对每个步骤的抽象,来完成程序- 例子:
- 孩子上学
1.妈妈起床
2.妈妈上厕所
3.妈妈洗漱
4.妈妈做早饭
5.妈妈叫孩子起床
6.孩子上厕所
7.孩子要洗漱
8.孩子吃饭
9.孩子背着书包上学校
- 孩子上学
- 例子:
- 面向过程指将我们的程序的逻辑分解为一个一个的步骤,
- 面向过程的编程的语言
- 面向过程的编程思想将一个功能分解为一个一个小的步骤,我们通过完成一个一个的小的步骤来完成一个程序
- 这种编程方式,符合我们人类的思维,编写起来相对比较简单
- 但是这种方式编写代码的往往只适用于一个功能,如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码,
所以它可复用性比较低,并且难于维护
- 面向对象的编程语言- 面向对象的编程语言,关注的是对象,而不关注过程- 对于面向对象的语言来说,一切都是对象- 例子:1.孩他妈起床叫孩子上学- 面向对象的编程思想,将所有的功能统一保存到对应的对象中比如,妈妈功能保存到妈妈的对象中,孩子的功能保存到孩子对象中要使用某个功能,直接找到对应的对象即可- 这种方式编写的代码,比较容易阅读,并且比较易于维护,容易复用。- 但是这种方式编写,不太符合常规的思维,编写起来稍微麻烦一点
简单归纳一下,面向对象的思想
- 找对象
- 搞对象
类(class)
- 我们目前所学习的对象都是Python内置的对象
- 但是内置对象并不能满足所有的需求,所以我们在开发中经常需要自定义一些对象
- 类,简单理解它就相当于一个图纸。在程序中我们需要根据类来创建对象
- 类就是对象的图纸!
- 我们也称对象是类的实例(instance)
- 如果多个对象是通过一个类创建的,我们称这些对象是一类对象
- 像 int() float() bool() str() list() dict() …. 这些都是类
- a = int(10) # 创建一个int类的实例 等价于 a = 10
- 我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名
- 类也是一个对象!
- 类就是一个用来创建对象的对象!
- 类是type类型的对象,定义类实际上就是定义了一个type类型的对象
示例:定义一个简单的类
# 定义一个简单的类# 使用class关键字来定义类,语法和函数很像!# class 类名([父类]):# 代码块class MyClass():passprint(MyClass) #得到: <class '__main__.MyClass'> 表示现在运行的是主文件的MyClass类
使用MyClass创建一个对象
使用类来创建对象,就像调用一个函数一样
# 使用MyClass创建一个对象mc = MyClass() # mc就是通过MyClass创建的对象,mc是MyClass的实例mc_2 = MyClass()mc_3 = MyClass()mc_4 = MyClass()# mc mc_2 mc_3 mc_4 都是MyClass的实例,他们都是一类对象# isinstance()用来检查一个对象是否是一个类的实例result = isinstance(mc_2,MyClass) #trueresult = isinstance(mc_2,str) #false
现在我们通过MyClass这个类创建的对象都是一个空对象。也就是对象中实际上什么都没有,就相当于是一个空的盒子
可以向对象中添加变量,对象中的变量称为属性。
语法:对象.属性名 = 属性值mc.name = '孙悟空'mc_2.name = '猪八戒'print(mc_2.name)
使用类创建对象的流程(参考下图)
1.创建一个变量<br /> 2.在内存中创建一个新对象<br /> 3.将对象的id赋值给变量

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

# 尝试定义一个表示人的类class Person :# 在类的代码块中,我们可以定义变量和函数# 在类中我们所定义的变量,将会成为所有的实例的公共属性# 所有实例都可以访问这些变量name = 'swk' # 公共属性,所有实例都可以访问# 在类中也可以定义函数,类中的定义的函数,我们称为方法# 这些方法可以通过该类的所有实例来访问def say_hello(self) :# 方法每次被调用时,解析器都会自动传递第一个实参# 第一个参数,就是调用方法的对象本身,# 如果是p1调的,则第一个参数就是p1对象# 如果是p2调的,则第一个参数就是p2对象# 一般我们都会将这个参数命名为self# say_hello()这个方法,可以显示如下格式的数据:# 你好!我是 xxx# 在方法中不能直接访问类中的属性print('你好!我是 %s' %self.name)# 创建Person的实例p1 = Person()p2 = Person()# print(p2.name)# 调用方法,对象.方法名()# 方法调用和函数调用的区别# 如果是函数调用,则调用时传几个参数,就会有几个实参# 但是如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参# 修改p1的name属性p1.name = '猪八戒'p2.name = '沙和尚'p1.say_hello() # '你好!我是 猪八戒'p2.say_hello() # '你好!我是 沙和尚'# del p2.name # 删除p2的name属性# print(p1.name)# print(p2.name)
类对象的初始化
目前来讲,对于Person类来说name是必须的,并且每一个对象中的name属性基本上都是不同,
而我们现在是将name属性在定义为对象以后,手动添加到对象中,这种方式很容易出现错误
# p1 = Person()# # 手动向对象添加name属性# p1.name = '孙悟空'# p2 = Person()# p2.name = '猪八戒'# p3 = Person()# p3.name = '沙和尚'
上面这样定义很麻烦
我们希望,在创建对象时,必须设置name属性,如果不设置对象将无法创建,并且属性的创建应该是自动完成的,而不是在创建对象以后手动完成。
在类中可以定义一些特殊方法(魔术方法)
# 特殊方法都是以__开头,__结尾的方法# 特殊方法不需要我们自己调用,不要尝试去调用特殊方法# p1.__init__() 不要这么做# 特殊方法将会在特殊的时刻自动调用# 学习特殊方法:# 1.特殊方法什么时候调用# 2.特殊方法有什么作用# 创建对象的流程# p1 = Person()的运行流程# 1.创建一个变量# 2.在内存中创建一个新对象# 3.__init__(self)方法执行# 4.将对象的id赋值给变量# init会在对象创建以后立即执行# init可以用来向新创建的对象中初始化属性# 调用类创建对象时,类后边的所有参数都会依次传递到init()中
#定义Person类class Person :def __init__(self,name):# print(self)# 通过self向新建的对象中初始化属性self.name = namedef say_hello(self):print('大家好,我是%s'%self.name)#定义实例p1 = Person('孙悟空')p2 = Person('猪八戒')p3 = Person('沙和尚')p4 = Person('唐僧')#输出nameprint(p1.name)print(p2.name)print(p3.name)print(p4.name)
类的基本结构
class 类名([父类]) :公共的属性...# 对象的初始化方法def __init__(self,...):...# 其他的方法def method_1(self,...):...def method_2(self,...):......
类的练习
定义一个表示dog的类
属性:name,age,gender,height...方法: jiao(),yao(),run()...
class Dog:'''表示狗的类'''def __init__(self , name , age , gender , height):self.name = nameself.age = ageself.gender = genderself.height = heightdef jiao(self):'''狗叫的方法'''print('汪汪汪~~~')def yao(self):'''狗咬的方法'''print('我咬你~~')def run(self):print('%s 快乐的奔跑着~~'%self.name)d = Dog('小黑',8,'male',30)# 目前我们可以直接通过 对象.属性 的方式来修改属性的值,这种方式导致对象中的属性可以随意修改# 非常的不安全,值可以任意修改,不论对错# 现在我们就需要一种方式来增强数据的安全性# 1.属性不能随意修改(我让你改你才能改,不让你改你就不能改)# 2.属性不能修改为任意的值(年龄不能是负数)d.name = '阿黄' #这些不应该被随意更改d.age = -10 #这些不应该被随意更改d.run()print(d.age)# print(d.name , d.age , d.gender , d.height)
类的封装
# 封装是面向对象的三大特性之一# 封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法# 如何隐藏一个对象中的属性?# - 将对象的属性名,修改为一个外部不知道的名字(最简单)class Dog:'''表示狗的类'''def __init__(self , name , age):self.hidden_name = nameself.hidden_age = agedef say_hello(self):print('大家好,我是 %s'%self.hidden_name)# 如何获取(修改)对象中的属性?# - 需要提供一个getter和setter方法使外部可以访问到属性# - getter 获取对象中的指定属性(get_属性名)# - setter 用来设置对象的指定属性(set_属性名)def get_name(self):'''get_name()用来获取对象的name属性'''# print('用户读取了属性')return self.hidden_namedef set_name(self , name):# print('用户修改了属性')self.hidden_name = namedef get_age(self):return self.hidden_agedef set_age(self , age):if age > 0 :self.hidden_age = age# 使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性# 1.隐藏了属性名,使调用者无法随意的修改对象中的属性# 2.增加了getter和setter方法,很好的控制的属性是否是只读的# 如果希望属性是只读的,则可以直接去掉setter方法# 如果希望属性不能被外部访问,则可以直接去掉getter方法# 3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的# 4.使用getter方法获取属性,使用setter方法设置属性# 可以在读取属性和修改属性的同时做一些其他的处理# 5.使用getter方法可以表示一些计算的属性
使用getter方法表示一些计算的属性:利用get计算矩形面积
class Rectangle:'''表示矩形的类'''def __init__(self,width,height):self.hidden_width = widthself.hidden_height = heightdef get_width(self):return self.hidden_widthdef get_height(self):return self.hidden_heightdef set_width(self , width):self.hidden_width = widthdef set_height(self , height):self.hidden_height = heightdef get_area(self):return self.hidden_width * self.hidden_height# r = Rectangle(5,2)# r.set_width(10)# r.set_height(20)# print(r.get_area())
利用下划线进一步的隐藏属性:(用了根没用一样,和改属性名字原理相同,不过是python内置)
# 可以为对象的属性使用双下划线开头,__xxx# 双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问# 其实隐藏属性只不过是Python自动为属性改了一个名字# 实际上是将名字修改为了,_类名__属性名 比如 __name -> _Person__nameclass Person:def __init__(self,name):self.__name = namedef get_name(self):return self.__namedef set_name(self , name):self.__name = namep = Person('孙悟空')print(p.__name) #__开头的属性是隐藏属性,无法通过对象访问p.__name = '猪八戒' #同样也无法修改print(p._Person__name)p._Person__name = '猪八戒'# print(p.get_name())# 使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用# 一般我们会将一些私有属性(不希望被外部访问的属性)以_开头# 一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性class Person:def __init__(self,name):self._name = namedef get_name(self):return self._namedef set_name(self , name):self._name = namep = Person('孙悟空')print(p._name)
property装饰器
简单理解就是把 p.set_name(“名字”) 装饰为 p.name = “名字” ,节省两个括号?
class Person:def __init__(self,name,age):self._name = nameself._age = age# property装饰器,用来将一个get方法,转换为对象的属性# 添加为property装饰器以后,我们就可以像调用属性一样使用get方法# 使用property装饰的方法,必须和属性名是一样的@propertydef name(self):print('get方法执行了~~~')return self._name# setter方法的装饰器:@属性名.setter@name.setterdef name(self , name):print('setter方法调用了')self._name = name@propertydef age(self):return self._age@age.setterdef age(self , age):self._age = agep = Person('猪八戒',18)p.name = '孙悟空'p.age = 28print(p.name,p.age)
类的继承
继承
# 定义一个类 Animal(动物)# 这个类中需要两个方法:run() sleep()class Animal:def run(self):print('动物会跑~~~')def sleep(self):print('动物睡觉~~~')# def bark(self):# print('动物嚎叫~~~')# 定义一个类 Dog(狗)# 这个类中需要三个方法:run() sleep() bark()class Dog:def run(self):print('狗会跑~~~')def sleep(self):print('狗睡觉~~~')def bark(self):print('汪汪汪~~~')# 有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能# 如何能让这个类来实现全部的功能呢?# ① 直接修改这个类,在这个类中添加我们需要的功能# - 修改起来会比较麻烦,并且会违反OCP原则# ② 直接创建一个新的类# - 创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,会出现大量的重复性代码# ③ 直接从Animal类中来继承它的属性和方法# - 继承是面向对象三大特性之一# - 通过继承我们可以使一个类获取到其他类中的属性和方法# - 在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super)# 子类(衍生类)可以直接继承父类中的所有的属性和方法## 通过继承可以直接让子类获取到父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则# 所以我们经常需要通过继承来对一个类进行扩展class Dog(Animal):def bark(self):print('汪汪汪~~~')def run(self):print('狗跑~~~~')class Hashiqi(Dog):def fan_sha(self):print('我是一只傻傻的哈士奇')d = Dog()h = Hashiqi()# 在创建类时,如果省略了父类,则默认父类为object# object是所有类的父类,所有类都继承自objectclass Person(object):pass# issubclass() 检查一个类是否是另一个类的子类# print(issubclass(Animal , Dog))# print(issubclass(Animal , object))# print(issubclass(Person , object))# isinstance()用来检查一个对象是否是一个类的实例# 如果这个类是这个对象的父类,也会返回True# 所有的对象都是object的实例print(isinstance(print , object))
类方法的重写
# 定义一个类 Animal(动物)# 这个类中需要两个方法:run() sleep()class Animal:def run(self):print('动物会跑~~~')def sleep(self):print('动物睡觉~~~')class Dog(Animal):def bark(self):print('汪汪汪~~~')def run(self):print('狗跑~~~~')# 如果在子类中如果有和父类同名的方法,则通过子类实例去调用方法时,# 会调用子类的方法而不是父类的方法,这个特点我们成为叫做方法的重写(覆盖,override)# 创建Dog类的实例# d = Dog()# d.run()# 当我们调用一个对象的方法时,# 会优先去当前对象中寻找是否具有该方法,如果有则直接调用# 如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法,# 如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错class A(object):def test(self):print('AAA')class B(A):def test(self):print('BBB')class C(B):def test(self):print('CCC')# 创建一个c的实例c = C()c.test()
super()
super() 可以用来动态获取当前类的父类
class Animal:def __init__(self,name):self._name = namedef run(self):print('动物会跑~~~')def sleep(self):print('动物睡觉~~~')@propertydef name(self):return self._name@name.setterdef name(self,name):self._name = name# 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法class Dog(Animal):def __init__(self,name,age):# 希望可以直接调用父类的__init__来初始化父类中定义的属性# super() 可以用来获取当前类的父类,# 并且通过super()返回对象调用父类方法时,不需要传递selfsuper().__init__(name)#直接调用父类的__init__来初始化name属性self._age = agedef bark(self):print('汪汪汪~~~')def run(self):print('狗跑~~~~')@propertydef age(self):return self._age@age.setterdef age(self,age):self._age = aged = Dog('旺财',18)print(d.name)print(d.age)
多重继承
class A(object):def test(self):print('AAA')class B(object):def test(self):print('B中的test()方法~~')def test2(self):print('BBB')# 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类# 可以在类名的()后边添加多个类,来实现多重继承# 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法# 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂# 如果多个父类中有同名的方法,则会现在第一个父类中寻找,然后找第二个,然后找第三个。。。# 前边父类的方法会覆盖后边父类的方法class C(A,B):pass# 类名.__bases__ 这个属性可以用来获取当前类的所有父类# print(C.__bases__) (<class '__main__.B'>,)# print(B.__bases__) (<class 'object'>,)# print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)c = C()c.test()
多态
多态是面向对象的三大特征之一,多态从字面上理解是多种形态
狗:(狼狗、藏獒、哈士奇、古牧 。。。)一个对象可以以不同的形态去呈现
# 定义两个类class A:def __init__(self,name):self._name = name@propertydef name(self):return self._name@name.setterdef name(self,name):self._name = nameclass B:def __init__(self,name):self._name = namedef __len__(self):return 10@propertydef name(self):return self._name@name.setterdef name(self,name):self._name = nameclass C:passa = A('孙悟空')b = B('猪八戒')c = C()# 定义一个函数# 对于say_hello()这个函数来说,只要对象中含有name属性,它就可以作为参数传递# 这个函数并不会考虑对象的类型,只要有name属性即可def say_hello(obj):print('你好 %s'%obj.name)# 在say_hello_2中我们做了一个类型检查,也就是只有obj是A类型的对象时,才可以正常使用,# 其他类型的对象都无法使用该函数,这个函数就违反了多态# 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型对象,这样导致函数的适应性非常的差# 注意,向isinstance()这种函数,在开发中一般是不会使用的!def say_hello_2(obj):# 做类型检查if isinstance(obj , A):print('你好 %s'%obj.name)say_hello(b) #可以调用say_hello_2(b) #不能调用# 鸭子类型# 如果一个东西,走路像鸭子,叫声像鸭子,那么它就是鸭子# len()# 之所以一个对象能通过len()来获取长度,是因为对象中具有一个特殊方法__len__# 换句话说,只要对象中具有__len__特殊方法,就可以通过len()来获取它的长度l = [1,2,3]s = 'hello'# print(len(l))# print(len(s))print(len(b)) #可以调用print(len(c)) #不能调用
面向对象的三大特征:
封装- 确保对象中的数据安全继承- 保证了对象的可扩展性多态- 保证了程序的灵活性
类的总结
类属性
# 定义一个类class A(object):count = 0# 类属性,直接在类中定义的属性是类属性# 类属性可以通过类或类的实例访问到# 但是类属性只能通过类对象来修改,无法通过实例对象修改a = A()print(A ,A.count) #可以访问print(a ,a.count) #可以访问a.count = 10 #无法通过实例对象修改,只影响a(实例)的属性
实例属性
class A(object):count = 0def __init__(self):self.name = '孙悟空'# 实例属性,通过实例对象添加的属性属于实例属性# 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
实例方法
class A(object):count = 0def __init__(self):self.name = '孙悟空'# 实例方法# 在类中定义,以self为第一个参数的方法都是实例方法# 实例方法在调用时,Python会将调用对象作为self传入# 实例方法可以通过实例和类去调用# 当通过实例调用时,会自动将当前调用对象作为self传入# 当通过类调用时,不会自动传递self,此时我们必须手动传递selfdef test(self):print('这是test方法~~~ ' , self)
类方法
class A(object):count = 0def __init__(self):self.name = '孙悟空'def test(self):print('这是test方法~~~ ' , self)# 类方法# 在类内部使用 @classmethod 来修饰的方法属于类方法# 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象# 类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls# 类方法可以通过类去调用,也可以通过实例调用,没有区别@classmethoddef test_2(cls):print('这是test_2方法,他是一个类方法~~~ ',cls)print(cls.count)
静态方法
class A(object):count = 0def __init__(self):self.name = '孙悟空'def test(self):print('这是test方法~~~ ' , self)@classmethoddef test_2(cls):print('这是test_2方法,他是一个类方法~~~ ',cls)print(cls.count)# 静态方法# 在类中使用 @staticmethod 来修饰的方法属于静态方法# 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用# 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数# 静态方法一般都是一些工具方法,和当前类无关@staticmethoddef test_3():print('test_3执行了~~~')
垃圾回收
就像我们生活中会产生垃圾一样,程序在运行过程当中也会产生垃圾,程序运行过程中产生的垃圾会影响到程序的运行的运行性能,所以这些垃圾必须被及时清理
没用的东西就是垃圾,在程序中没有被引用的对象就是垃圾,这种垃圾对象过多以后会影响到程序的运行的性能,所以我们必须进行及时的垃圾回收,所谓的垃圾回收就是讲垃圾对象从内存中删除
在Python中有自动的垃圾回收机制,它会自动将这些没有被引用的对象删除,所以我们不用手动处理垃圾回收
class A:def __init__(self):self.name = 'A类'# del是一个特殊方法,它会在对象被垃圾回收前调用def __del__(self):print('A()对象被删除了~~~',self)a = A()b = a # 又使用一个变量b,来引用a对应的对象print(a.name)# a = None # 将a设置为了None,此时没有任何的变量对A()对象进行引用,它就是变成了垃圾# b = None
特殊方法
特殊方法,也称为魔术方法, 特殊方法都是使用__开头和结尾的
特殊方法一般不需要我们手动调用,需要在一些特殊情况下自动执行
# 定义一个Person类class Person(object):"""人类"""def __init__(self, name , age):self.name = nameself.age = age# __str__()这个特殊方法会在尝试将对象转换为字符串的时候调用# 它的作用可以用来指定对象转换为字符串的结果 (print函数)def __str__(self):return 'Person [name=%s , age=%d]'%(self.name,self.age)# __repr__()这个特殊方法会在对当前对象使用repr()函数时调用# 它的作用是指定对象在 ‘交互模式’中直接输出的效果def __repr__(self):return 'Hello'#一系列特殊方法# object.__add__(self, other)# object.__sub__(self, other)# object.__mul__(self, other)# object.__matmul__(self, other)# object.__truediv__(self, other)# object.__floordiv__(self, other)# object.__mod__(self, other)# object.__divmod__(self, other)# object.__pow__(self, other[, modulo])# object.__lshift__(self, other)# object.__rshift__(self, other)# object.__and__(self, other)# object.__xor__(self, other)# object.__or__(self, other)# object.__lt__(self, other) 小于 <# object.__le__(self, other) 小于等于 <=# object.__eq__(self, other) 等于 ==# object.__ne__(self, other) 不等于 !=# object.__gt__(self, other) 大于 ># object.__ge__(self, other) 大于等于 >=# __len__()获取对象的长度# object.__bool__(self)# 可以通过bool来指定对象转换为布尔值的情况def __bool__(self):return self.age > 17# __gt__会在对象做大于比较的时候调用,该方法的返回值将会作为比较的结果# 他需要两个参数,一个self表示当前对象,other表示和当前对象比较的对象# self > otherdef __gt__(self , other):return self.age > other.age# 创建两个Person类的实例p1 = Person('孙悟空',18)p2 = Person('猪八戒',28)# 打印p1# 当我们打印一个对象时,实际上打印的是对象的中特殊方法 __str__()的返回值# print(p1) # <__main__.Person object at 0x04E95090># print(p1)# print(p2)# print(repr(p1))# t = 1,2,3# print(t) # (1, 2, 3)# print(p1 > p2)# print(p2 > p1)# print(bool(p1))# if p1 :# print(p1.name,'已经成年了')# else :# print(p1.name,'还未成年了')
模块
模块的创建和引入
模块(module)模块化,模块化指将一个完整的程序分解为一个一个小的模块
通过将模块组合,来搭建出一个完整的程序
不采用模块化,统一将所有的代码编写到一个文件中 .采用模块化,将程序分别编写到多个文件中
模块化的优点: ① 方便开发 ② 方便维护 ③ 模块可以复用!
在Python中一个py文件就是一个模块,要想创建模块,实际上就是创建一个python文件。
注意:模块名要符号标识符的规范。
在一个模块中引入外部模块
① import 模块名 (模块名,就是python文件的名字,注意不要py)。
② import 模块名 as 模块别名。
- 可以引入同一个模块多次,但是模块的实例只会创建一个。
- import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头。
- 在每一个模块内部都有一个name属性,通过这个属性可以获取到模块的名字。
- name属性值为 main的模块是主模块,一个程序中只会有一个主模块。主模块就是我们直接通过 python 执行的模块
引入一个叫test_module的模块:
import test_module as test# print(test.__name__)print(__name__) #获取到模块的名字: __main__
模块的使用
创建一个模块:m.py
# 可以在模块中定义变量,在模块中定义的变量,在引入模块后,就可以直接使用了a = 10b = 20# 添加了_的变量,只能在模块内部访问,在通过import * 引入时,不会引入_开头的变量_c = 30# 可以在模块中定义函数,同样可以通过模块访问到def test():print('test')def test2():print('test2')# 也可以定义类class Person:def __init__(self):self.name = '孙悟空'# 编写测试代码,这部分代码,只要当当前文件作为主模块的时候才需要执行# 而当模块被其他模块引入时,不需要执行的,此时我们就必须要检查当前模块是否是主模块if __name__ == '__main__':test()test2()p = Person()print(p.name)
主程序:
import m #引入模块# # 访问模块中的变量:模块名.变量名# # print(m.a , m.b)# # m.test2()# p = m.Person()# print(p.name)def test2():print('这是主模块中的test2')# 也可以只引入模块中的部分内容# 语法 from 模块名 import 变量,变量....from m import Personfrom m import testfrom m import Person,testfrom m import * # 引入到模块中所有内容,一般不会使用p1 = Person()print(p1)test()test2()# 也可以为引入的变量使用别名# 语法:from 模块名 import 变量 as 别名from m import test2 as new_test2test2()new_test2()from m import *# print(_c)
包
包 Package。包也是一个模块
当我们模块中代码过多时,或者一个模块需要被分解为多个模块时,这时就需要使用到包。
普通的模块就是一个py文件,而包是一个文件夹
包中必须要一个一个 init.py 这个文件,这个文件中可以包含有包中的主要内容

引入一个叫hello的包。
from hello import a , bprint(a.c)print(b.d)
# __pycache__ 是模块的缓存文件# py代码在执行前,需要被解析器先转换为机器码,然后再执行# 所以我们在使用模块(包)时,也需要将模块的代码先转换为机器码然后再交由计算机执行# 而为了提高程序运行的性能,python会在编译过一次以后,将代码保存到一个缓存文件中# 这样在下次加载这个模块(包)时,就可以不再重新编译而是直接加载缓存中编译好的代码即可
python标准库
开箱即用。为了实现开箱即用的思想,Python中为我们提供了一个模块的标准库。
在这个标准库中,有很多很强大的模块我们可以直接使用,并且标准库会随Python的安装一同安装。
sys模块
# sys模块,它里面提供了一些变量和函数,使我们可以获取到Python解析器的信息# 或者通过函数来操作Python解析器# 引入sys模块import sys# sys.argv# 获取执行代码时,命令行中所包含的参数# 该属性是一个列表,列表中保存了当前命令的所有参数print(sys.argv)# sys.path# 他是一个列表,列表中保存的是模块的搜索路径# ['C:\\Users\\lilichao\\Desktop\\resource\\course\\lesson_06\\code',# 'C:\\dev\\python\\python36\\python36.zip',# 'C:\\dev\\python\\python36\\DLLs',# 'C:\\dev\\python\\python36\\lib',# 'C:\\dev\\python\\python36',# 'C:\\dev\\python\\python36\\lib\\site-packages']print.pprint(sys.path)# sys.platform# 表示当前Python运行的平台print(sys.platform)# sys.exit()# 函数用来退出程序# sys.exit('程序出现异常,结束!')print('hello')
pprint 模块
# pprint 模块它给我们提供了一个方法 pprint() 该方法可以用来对打印的数据做简单的格式化import pprint# sys.modules# 获取当前程序中引入的所有模块# modules是一个字典,字典的key是模块的名字,字典的value是模块对象pprint.pprint(sys.modules)
os模块
# os 模块让我们可以对操作系统进行访问import os# os.environ# 通过这个属性可以获取到系统的环境变量pprint.pprint(os.environ['path'])# os.system()# 可以用来执行操作系统的名字# os.system('dir')os.system('notepad')
第七部分 异常和文件
异常
什么是异常
程序在运行过程当中,不可避免的会出现一些错误,比如:
使用了没有赋值过的变量
使用了不存在的索引
除0
…
这些错误在程序中,我们称其为异常。
程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全部都不会执行!
处理异常
程序运行时出现异常,目的并不是让我们的程序直接终止!
Python是希望在出现异常时,我们可以编写代码来对异常进行处理!
try语句
try语句try:代码块(可能出现错误的语句)except 异常类型 as 异常名:代码块(出现错误以后的处理方式)except 异常类型 as 异常名:代码块(出现错误以后的处理方式)except 异常类型 as 异常名:代码块(出现错误以后的处理方式)else:代码块(没出错时要执行的语句)finally:代码块(该代码块总会执行)# try是必须的 else语句有没有都行 except和finally至少有一个
如果出现错误,则会执行expect子句中的代码,这样我们就可以通过代码来处理异常
避免因为一个异常导致整个程序的终止
异常的传播
当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,。如果函数中没有对异常进行处理,则异常会继续向函数调用处传播,
如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播,直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息。
异常的对象
当程序运行过程中出现异常以后,所有的异常信息会被保存一个专门的异常对象中,而异常传播时,实际上就是异常对象抛给了调用处
比如 : ZeroDivisionError类的对象专门用来表示除0的异常, NameError类的对象专门用来处理变量错误的异常(在Python为我们提供了多个异常对象 )
print('异常出现前')l = []try:# print(c)# l[10]# 1 + 'hello'print(10/0)except NameError:# 如果except后不跟任何的内容,则此时它会捕获到所有的异常# 如果在except后跟着一个异常的类型,那么此时它只会捕获该类型的异常print('出现 NameError 异常')except ZeroDivisionError:print('出现 ZeroDivisionError 异常')except IndexError:print('出现 IndexError 异常')# Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常# 可以在异常类后边跟着一个 as xx 此时xx就是异常对象except Exception as e :print('未知异常',e,type(e))finally :print('无论是否出现异常,该子句都会执行')print('异常出现后')
抛出异常
可以使用 raise 语句来抛出异常,raise语句后需要跟一个异常类 或 异常的实例
class MyError(Exception):passdef add(a,b):# 如果a和b中有负数,就向调用处抛出异常if a < 0 or b < 0:# raise用于向外部抛出异常,后边可以跟一个异常类,或异常类的实例# raise Exception# 抛出异常的目的,告诉调用者这里调用时出现问题,希望你自己处理一下# raise Exception('两个参数中不能有负数!')raise MyError('自定义的异常')# 也可以通过if else来代替异常的处理# return Noner = a + breturn rprint(add(-123,456))
文件(File)
通过Python程序来对计算机中的各种文件进行增删改查的操作 I/O(Input / Output)
操作文件的步骤:
① 打开文件<br /> ② 对文件进行各种操作(读、写),然后保存<br /> ③ 关闭文件
打开文件
当前文件结构:

使用open函数来打开一个文件:
open(file, mode='r', buffering=-1, encoding_=None, errors=None, newline=None, closefd=True, opener=None)# 使用open函数来打开一个文件# 参数:# file 要打开的文件的名字(路径)# 返回值:# 返回一个对象,这个对象就代表了当前打开的文件# 创建一个变量,来保存文件的名字# 如果目标文件和当前文件在同一级目录下,则直接使用文件名即可file_name = 'demo.txt'# 在windows系统使用路径时,可以使用/来代替 \# 或者可以使用 \\ 来代替 \# 或者也可以使用原始字符串(加r)file_name = 'hello\\demo.txt'file_name = r'hello\demo.txt'# 表示路径,可以使用..来返回一级目录file_name = '../hello/demo.txt'# 如果目标文件距离当前文件比较远,此时可以使用绝对路径# 绝对路径应该从磁盘的根目录开始书写file_name = r'C:\Users\lilichao\Desktop\hello.txt'file_obj = open(file_name) # 打开 file_name 对应的文件print(file_obj)
打开文件代码基本结构:
# 打开文件file_name = 'demo.txt'# 调用open()来打开文件file_obj = open(file_name)# # 当我们获取了文件对象以后,所有的对文件的操作都应该通过对象来进行# # 读取文件中的内容# # read()方法,用来读取文件中的内容,它会将内容全部保存为一个字符串返回content = file_obj.read()print(content)
关闭文件
调用close()方法来关闭文件
# # 关闭文件# # 调用close()方法来关闭文件file_obj.close() #不常用# with ... as 语句with open(file_name) as file_obj :# # 在with语句中可以直接使用file_obj来做文件操作# # 此时这个文件只能在with中使用,一旦with结束则文件会自动close()# print(file_obj.read())
完善结构:
file_name = 'hello'try:with open(file_name) as file_obj :print(file_obj.read())except FileNotFoundError:print(f'{file_name} 文件不存在~~')
文件读取
注意:
调用open()来打开一个文件,可以将文件分成两种类型:
一种,是纯文本文件(使用utf-8等编码编写的文本文件)
一种,是二进制文件(图片、mp3、ppt等这些文件)
open()打开文件时,默认是以文本文件的形式打开的,但是open()默认的编码为None
所以处理文本文件时,必须要指定文件的编码
with open(file_name,encoding='utf-8') as file_obj:
通过 read() 来读取文件中的内容
content = file_obj.read(6)content = file_obj.read(-1)
如果直接调用read()它会将文本文件的所有内容全部都读取出来,如果要读取的文件较大的话,会一次性将文件的内容加载到内存中,容易导致内存泄漏,所以对于较大的文件,不要直接调用read()
file_name = 'demo2.txt'try:with open(file_name,encoding='utf-8') as file_obj:# content = file_obj.read(-1)content = file_obj.read(6)content = file_obj.read(6)content = file_obj.read(6)content = file_obj.read(6)# print(content)# print(len(content))except FileNotFoundError :print(f'{file_name} 这个文件不存在!')
read()可以接收一个size作为参数,该参数用来指定要读取的字符的数量, 默认值为-1,它会读取文件中的所有字符,可以为size指定一个值,这样read()会读取指定数量的字符。
每一次读取都是从上次读取到位置开始读取的,如果字符的数量小于size,则会读取剩余所有的,如果已经读取到了文件的最后了,则会返回’’空串
读取大文件的方式
# 读取大文件的方式file_name = 'demo.txt'try:with open(file_name,encoding='utf-8') as file_obj:# 定义一个变量,来保存文件的内容file_content = ''# 定义一个变量,来指定每次读取的大小chunk = 100# 创建一个循环来读取文件内容while True:# 读取chunk大小的内容content = file_obj.read(chunk)# 检查是否读取到了内容if not content:# 内容读取完毕,退出循环break# 输出内容# print(content,end='')file_content += contentexcept FileNotFoundError :print(f'{file_name} 这个文件不存在!')print(file_content)
其它读取方式:
readline() readlines()
import pprintimport osfile_name = 'demo.txt'with open(file_name , encoding='utf-8') as file_obj:# readline()# 该方法可以用来读取一行内容print(file_obj.readline(),end='')# print(file_obj.readline())# print(file_obj.readline())# readlines()# 该方法用于一行一行的读取内容,它会一次性将读取到的内容封装到一个列表中返回r = file_obj.readlines()pprint.pprint(r[0])# pprint.pprint(r[1])# pprint.pprint(r[2])for t in file_obj:print(t)d
二进制文件的读取
file_name = 'c:/Users/lilichao/Desktop/告白气球.flac'#读取一个音乐文件# 读取模式# t 读取文本文件(默认值)# b 读取二进制文件with open(file_name , 'rb') as file_obj:# 读取文本文件时,size是以字符为单位的# 读取二进制文件时,size是以字节为单位# print(file_obj.read(100))
将读取到的内容写出来
# 将读取到的内容写出来# 定义一个新的文件new_name = 'aa.flac'with open(new_name , 'wb') as new_obj:# 定义每次读取的大小chunk = 1024 * 100 #每次读取100Kwhile True :# 从已有的对象中读取数据content = file_obj.read(chunk)# 内容读取完毕,终止循环if not content :break# 将读取到的数据写入到新对象中new_obj.write(content)
文件的写入
file_name = 'demo5.txt'# 使用open()打开文件时必须要指定打开文件所要做的操作(读、写、追加)# 如果不指定操作类型,则默认是 读取文件 , 而读取文件时是不能向文件中写入的# r 表示只读的 (默认值)# w 表示是可写的,使用w来写入文件时,如果文件不存在会创建文件,如果文件存在则会截断文件# 截断文件指删除原来文件中的所有内容# a 表示追加内容,如果文件不存在会创建文件,如果文件存在则会向文件中追加内容# x 用来新建文件,如果文件不存在则创建,存在则报错# + 为操作符增加功能# r+ 即可读又可写,文件不存在会报错# w+# a+# with open(file_name , 'w' , encoding='utf-8') as file_obj:# with open(file_name , 'r+' , encoding='utf-8') as file_obj:with open(file_name , 'x' , encoding='utf-8') as file_obj:# write()来向文件中写入内容,# 如果操作的是一个文本文件的话,则write()需要传递一个字符串作为参数# 该方法会可以分多次向文件中写入内容# 写入完成以后,该方法会返回写入的字符的个数file_obj.write('aaa\n')file_obj.write('bbb\n')file_obj.write('ccc\n')r = file_obj.write(str(123)+'123123\n')r = file_obj.write('今天天气真不错')print(r)
读取文件的位置
# with open('demo.txt','rb') as file_obj:# # print(file_obj.read(100))# # print(file_obj.read(30))# # seek() 可以修改当前读取的位置# file_obj.seek(55)# file_obj.seek(80,0)# file_obj.seek(70,1)# file_obj.seek(-10,2)# # seek()需要两个参数# # 第一个 是要切换到的位置# # 第二个 计算位置方式# # 可选值:# # 0 从头计算,默认值# # 1 从当前位置计算# # 2 从最后位置开始计算# print(file_obj.read())# # tell() 方法用来查看当前读取的位置# print('当前读取到了 -->',file_obj.tell())with open('demo2.txt','rt' , encoding='utf-8') as file_obj:# print(file_obj.read(100))# print(file_obj.read(30))# seek() 可以修改当前读取的位置file_obj.seek(9)# seek()需要两个参数# 第一个 是要切换到的位置# 第二个 计算位置方式# 可选值:# 0 从头计算,默认值# 1 从当前位置计算# 2 从最后位置开始计算print(file_obj.read())# tell() 方法用来查看当前读取的位置print('当前读取到了 -->',file_obj.tell())
文件的其他操作(和操作系统命令行相似)
import osfrom pprint import pprint# os.listdir() 获取指定目录的目录结构# 需要一个路径作为参数,会获取到该路径下的目录结构,默认路径为 . 当前目录# 该方法会返回一个列表,目录中的每一个文件(夹)的名字都是列表中的一个元素r = os.listdir()# os.getcwd() 获取当前所在的目录r = os.getcwd()# os.chdir() 切换当前所在的目录 作用相当于 cd# os.chdir('c:/')# r = os.getcwd()# 创建目录# os.mkdir("aaa") # 在当前目录下创建一个名字为 aaa 的目录# 删除目录# os.rmdir('abc')# open('aa.txt','w')# 删除文件# os.remove('aa.txt')# os.rename('旧名字','新名字') 可以对一个文件进行重命名,也可以用来移动一个文件# os.rename('aa.txt','bb.txt')os.rename('bb.txt','c:/users/lilichao/desktop/bb.txt')pprint(r)
END:Duruofu 2022.4.27于西安理工大学
