前段时间在学习python时整理了一些笔记,同时还有每个知识点的练习代码还没加上,看看找个时间一起上传,如果有哪些地方写错了请多谅解。
基础知识
变量
- 无需声明直接使用
- 可以赋任意值,也可以任意修改
- 不能使用没有赋值的变量
标识符
组成
1.大小写字母
2.数字
3.下划线_
规则
-
不能够使用数字开头
-
不能是关键字和保留字(还有函数名)
以上两条规则若不遵循,报错:SyntaxError:invalid syntax -
遵循法则:
下划线命名法:所有字母小写,单词间用_分割
帕斯卡命名法(驼峰命名法):单词开头大写,其余字母小写
占位符
%s 字符串
%f 浮点数
%d 整数
数据类型
一.数值分为:整数,浮点数,复数
整数(int)
-
整数大小无限制
-
长度过长使用下划线分隔
-
十进制不能以0开头
-
其他进制以十进制打印
二进制(0b)
八进制(0o)
十六进制(0x)
浮点数(float)
浮点数运算结果不精确
二.字符串表示文本信息
字符串需要使用引号(单引号或双引号)
-
引号不能混用
-
相同引号不能嵌套
-
引号不能跨行使用
三重引号可跨行使用,且保留字符串格式(’’'或""")
-
使用转义字符\表示特殊字符
’ ’
" "
\t 制表符
\n 换行符
\ \
格式化字符串
-
两个字符串可以相加拼接
字符串不能和其他类型进行加法运算
错误:TypeError:must be str
-
多个参数
参数间用逗号隔开
-
创建时,可以使用占位符
%3s 限定字符显示个数(不足用空格填补)
%3.5s 限定字符显示个数在3-5之间
-
格式化字符串(直接嵌入变量)
例:c=f’hello {a} {b}’(设a,b已存在)
字符串的复制
字符串与数字相乘即可复制
三.布尔值
主要用来做逻辑判断
- 布尔值实际上也属于整型
- 有两个值:True(1) 和 False(0)
四,空值
None(空值)用于表示不存在
类型检查
检查变量的类型
type()用来检查值的类型
该函数将检查结果作为返回值返回,可使用变量来接收函数的返回值
对象(object)
对象是内存中专门用来存储指定数据的一块区域(容器)。
- python是面向对象的语言。
- 在python里一切皆对象。
- 程序运行中,所有数据都是存储到内存中然后再运行。
对象的结构
-
id(标识)
id用来表示对象的唯一性,是对象的内存地址,由解析器生成,可以同过id()函数查看对象的id
id一旦创建,id不能改变
-
type(类型)
类型标识当前对象的所属类型,决定对象有哪些功能,可以通过type()函数查看对象的类型。
对象一旦创建类型不能修改
-
value(值)
改对象:通过变量去修改对象的值,不改变变量所指的对象值是对象中存储的具体数据。
有些对象的值是可变的。
对象的分类
一.可变对象
可变对象的值可变。
-
改对象:通过变量去修改对象的值,不改变变量所指的对象。当修改对象时,如有其他变量也指向该对象,修改也同时体现在其他变量。
-
改变量:给变量重新赋值,改变变量所指的对象。为一个变量重新赋值,不影响其他变量。
-
属于可变对象:列表
一般只有为变量赋值时才是修改变量,其余是修改对象。
二.不可变对象
不可变对象的值不可变。
变量和对象
- 对象没有直接存储在变量中,变量像是给对象起的别名。
- 变量中存储的不是便变量的值,而是对象的id(内存地址)
- 变量中保存的对象,只有在变量重新赋值时才会改变。
- 变量和变量之间是相互独立的。
类型转换
将一个类型的对象转换成其他对象。类型转换不是改变对象本身的类型,而是将对象的值转换为新的对象。
类型转换的四个函数
如要修改原变量的对象类型,需要对变量重新赋值。
-
int()函数:将其他类型转换成整型。
例:a=‘123’
a=int(a)
规则:
-
布尔值:True=1,False=0
-
浮点数:取整,省略小数
-
字符串:整数字符串直接转换为对应数字;不合法的整数字符串,不能转换会报错。
报错:ValueError:invalid literal for int() with base xxx……
-
none类型:不能转换为int类型。
报错:TypeError:int() argument must be a string,a bytes-like object or a number,not ‘NoneType’
-
-
float()函数:将其他类型转换成浮点型。
规则:
- 浮点型转换规则同整数类型转换。
-
str()函数:将其他类型转换成字符串。
规则:
- 布尔值:True->‘True’,False->‘False’
- 字符串转换规则同整数类型转换。
-
bool()函数:将其他类型转换成布尔值。
规则:
- 所有空的对象都会转换为False;其余转换为True
运算符
运算符可以对一个或多个值进行运算或各种操作。
运算符的分类
一.算术运算符
-
加法运算符(+)
-
减法运算符(-)
-
乘法运算符(*)
-
除法运算符(/)
- 运算时结果总会返回浮点型
- 除数不能为0
错误:ZeroDivisionError:division by zero
-
整除运算符(//):总会返回整型
-
幂运算符(**):求值的几次幂
-
取余运算符(%)
二.赋值运算符
- =(向左赋值)
- +=,-=,*=,/=,**=,//=,%=
对浮点数做运算时,结果会返回整数
三.关系运算符
比较两个值之间的关系,返回一个布尔值,如果成立返回true,否则返回false。
-
,>=,<,<=,==,!=
-
在python中可以对两个字符串进行进行比较,在比较时,实际上比较的是字符的unicode编码
在比较编码时,是逐位比较的,利用该特性可以对字符串按照字母顺序进行排序,但对中文字符无意义
如不希望比较unicode编码,则需要转换为数字再比较
-
is,is not
比较两个对象的关系,通过比较对象的id实现。
-
==、!=和is、is not的关系
==、!=:比较对象的值是否相等。
is、is not:比较对象的id是否相等。
四.逻辑运算符
主要用来做逻辑判断,可以连着使用.
- and 逻辑与(有False即为False)
- or 逻辑或(有True即为True)
- not 逻辑非(True是False,False是True)
对于布尔值取反;对于非布尔值先转换为布尔值再取反。
非布尔值的与或运算
非布尔值进行逻辑运算,将其当作布尔值运算,最后返回原值。
- and 逻辑与(顺序找False)
- or 逻辑或(顺序找True)
五.条件运算符(三元运算符)
语法:语句1 if 条件表达式 else 语句2
流程:先对条件表达式求值判断,结果为True,执行语句1;结果为False,执行语句2,最后返回执行结果。
六.运算符的优先级
查看优先级表格(越靠下优先级越高)
- 优先级一样,自左向右按顺序执行
- 优先级越高,越优先计算
可通过小括号改变优先顺序
流程控制语句
代码是自上向下顺序执行.通过流程控制语句,可以改变程序执行的顺序,也可以让程序执行多次。
条件判断语句
一.if语句
语法:
if 条件表达式:语句
或
if 条件表达式:
代码块
流程:对表达式进行求值判断,结果为True,执行语句;结果为False,不执行语句。
- 通常情况下,if语句只控制紧随其后的那条语句。
- 如要控制多个语句(代码块),则需要缩进。
缩进
- tab键
- 4个空格键(推荐)
- 缩进方式必须统一
二.if-else语句
语法:
if 条件表达式:
代码块
else:
代码块
流程:对表达式进行求值判断,结果为True,执行if语句的代码块;结果为False,执行else语句的代码块.
三.if-elif-else语句
语法:
if 条件表达式:
代码块
elif 表达式:
代码块
else:
代码块
流程:自上向下对表达式进行求值判断,结果为True,执行当前语句的代码块,语句结束;结果为False,继续向下判断,直到所有表达式都为False,则执行else语句的代码块.
只有一个代码块执行
循环语句
使指定的代码块重复执行指定的次数。
循环的三个要点:
- 初始化表达式 i=0
- 条件表达式 i<10
- 更新表达式 i++
循环嵌套
外层循环一次,内层循环执行
一.while循环语句
语法:
while 条件表达式:
代码块
else:
代码块
流程:先对条件表达式进行求值判断,结果为True,执行while循环语句的代码块,继续对条件表达式进行求值判断直到结果为False,循环终止。如果循环有对应的else,则执行else语句的代码块。
条件恒为ture的循坏语句称为死循环,慎用!
二.for循环语句
语法:
for 条件表达式:
代码块
流程:先对条件表达式进行条件判断,符合条件,执行for循环语句的代码块,继续对条件表达式进行判断直到不符合条件,循环终止。
三.break和continue
- break语句:用来立即退出循环语句(包括else)
- continue语句:跳过当次循环中continue后的语句
- pass:是用来在判断和循环语句中占位的
序列
一.列表(list)
列表是python中的一个对象,可以保存多个有序的数据。
列表的特性
-
元素:是列表中的数据。
-
列表是储存对象的对象。
-
列表可以保存任何对象。(不推荐)
-
列表中的元素按照插入的顺序保存。
-
通过索引(index)获取列表中的元素。
-
索引是元素在列表中的位置,每个元素都有一个索引,从0开始,以此类推。
-
使用索引超过最大范围会引起异常。
错误:IndexError:list index out of range
-
使用len()函数获取列表长度。
列表的切片
切片指从现有的列表中,获取一个子列表。
-
列表的索引为负数,则从后向前获取元素。
-1表示列表的倒数第一个元素,以此类推。
-
获取列表的指定元素,包括起始位置的元素,但不包括结束位置的元素,返回一个新列表,不影响原列表。
语法:列表名[起始:结束:步长]
-
起始和结束位置的索引可以省略,显示列表的全部元素。
-
省略起始位置的索引,从列表的第一个元素截取。
-
省略结束位置的索引,截取到最后一个元素。
-
步长表示每次获取元素的间隔,默认为1。
-
步长不能是0,但可以是负值,步长为负值,则列表从后向前获取。
错误:ValueError:slice step cannot be zero
修改列表的元素
只适用于可变序列,不可变序列(字符串)无法通过索引修改。
-
直接通过索引来修改元素
-
通过del删除元素
-
通过切片修改元素
- 切片赋值时,只能使用序列
- 当设置步长时,序列中元素个数必须也切片中的元素个数一致
- 当切片赋值为空列表时,删除切片中的元素
-
列表的方法
- append():在列表的最后添加一个元素。
- insert():在列表指定位置插入一个元素。
- extend():使用新序列来拓展当前序列。
- clear():清空序列。
- pop():删除指定索引的元素并返回。默认值是最后一个元素。
- remove():删除指定值,相同值有多个只删除第一个。
- reverse():反转序列。
- sort():对元素进行排序,默认升序,降序写法:sort(reverse=True)。
-
遍历元素
将列表的所有元素取出来。
- len():取列表的长度。
- 通过while循环遍历
- 通过for循环遍历
-
不可变序列可通过list()函数改为可变序列,然后进行按以上操作修改。
二.元组(tuple)
元组是一个不可变的序列。操作跟列表一致。
元组的特性
-
使用()创建元组
-
元组是不可变对象,不能为元组中的元素重新赋值。
错误:TypeError:‘tuple’ object does not support item assignment
-
当元组不是空组时,括号可以省略。
-
如果元组不是空元组,至少有一个元素和逗号。
元组的解包(解构)
解包指将元组中的每一个元素都赋给一个变量。
-
可利用解包的方法交换a,b的值
-
在对元组解包时,变量数量必须和元组中的元素数量一致。
-
若将变量前添加星号(),变量将获取元组中所有剩余的元素,该变量的类型是列表。但是不能同时出现两个或以上变量。
错误:SyntaxError:two starred experssions in assignment
字典(dict)
字典属于一种新的数据结构,称为映射(mapping)。
字典的特性
-
作用和列表类似,都是用来存储对象的容器。
-
列表存储对象的性能很好,但是查询数据的性能很差。
-
字典中的每个元素都有唯一的一个键(key),通过键可以快速查找到指定的元素。
在查询元素时,字典的效率非常快
-
在字典中可以保存多个对象,每个对象都有一个唯一的名字。
对象:称为值(value)
唯一的名字:称为键(key)
字典也称为键值对(key-value)结构
字典中可以有多个键值对,每个键值对称为项(item)
-
字典的值可以是任意对象。
-
字典的键可以是任意的不可变对象(int,str,bool,tuple…),一般使用str
字典的键是唯一的,如重复使用最后使用的键会覆盖前面的值。
字典的使用
-
使用{}或dict()创建列表
-
创建一个保护数据的字典
语法:{key:value,key:value;}
-
根据键获取值
-
语法:字典名[键名]
使用不存在的键会报错(错误:KeyError:…)
-
语法:字典名.get(key,默认值)
如获取的键不存在,返回默认值None,可以指定默认值,作为第二参数。
-
-
可以将一个包含有双值子序列的序列转换为字典。
双值子序列指序列中只有两个值,例如:[1,3],(‘a’,3),‘ab’,‘abcc’
-
修改字典
-
获取
语法:字典名.[key]
通过键获取字典中的值,如不存在,抛出异常:KeyError
语法:字典名.get(key,default)
可以添加其他字典的key-value,如键不存在,返回None,也可指定默认值,取不到值将返回默认值。
-
添加,修改
语法:字典名.[key]=value
键存在修改,不存在则添加。
语法:字典名.setdefault(key,default)
可以添加key-value,如键存在,返回值不修改字典,如不存在,添加键值对。
语法:字典名.update(key,default)
可以添加其他字典的key-value,如键存在,替换后面的值。
-
删除
语法:del 字典名[key]
如删除不存在的键,会报错。(错误:KeyError:…)
语法:字典名.popitem()
随机删除字典中的一个键值对,一般是最后一个,然后返回被删键值对(元组)。
当删除空字典,会出现错误:KeyError:‘popitem():dictionary is empty’
语法:字典名.pop(key,default)
通过键删除字典中的一个键值对,然后返回被删除的值。
如删除不存在的键,会报错;若指定默认值,则返回默认值。
语法:字典名.clear()
清空字典。
-
复制
语法:字典名2=字典名1
指向同一个对象。
-
浅复制:语法:字典名2=字典名1.copy()
复制后的对象与原对象相互独立,修改其中一个不影响另一个对象。
浅复制只简单复制对象内部的值,若值是可变对象,该对象不会被复制。
-
深复制:语法:deepcopy()
-
-
遍历
语法:字典名.keys()
返回保存字典所有键的序列。
语法:字典名.values()
返回保存字典所有值的序列。
语法:字典名.items()
返回保存字典所有双值子序列的序列。
-
-
字典的方法
len():获取字典的键值对个数。
in:检查字典中是否包含指定的键。
not in:检查字典中是否不包含指定的键。
集合(set)
集合和列表非常相似。
集合的特性
1.只能存储不可变对象。
列表是可变对象,存储列表会出现错误:typeError:unhashble Type: ‘list’
2.存储的对象是无序的(不按元素插入顺序保存)。
3.不能出现重复的元素。
集合的使用
-
使用{}表示,用set()来创建集合
语法: 变量 = set({ }) 或 变量 = set()
set()可以将序列和字典(只保存键)转换为集合。
-
获取元素
语法:list(集合名)[序号]
先通过list()转换成列表。
-
修改集合
-
添加
语法:集合名.add(元素)
向集合添加元素,重复不添加到集合。
语法:集合名.update(x)
向当前集合添加另一个集合x(可以是序列或字典)的元素,重复不添加到集合。
-
删除
语法:集合名.pop(key,default)
随机删除集合的一个元素。
如删除不存在的键,会报错;若指定默认值,则返回默认值。
语法:集合名.remove()
删除集合中的指定元素。
语法:集合名.clear()
清空集合。
-
复制
浅复制:语法:集合2=集合1.copy()
复制后的对象与原对象相互独立。
-
-
集合的运算
对集合进行运算时,将运算的结果返回,不影响原来的结果。
-
交集运算:&
-
并集运算:|
-
差集运算:-
-
异或集运算:^
只在其中一个集合中出现的元素。
-
检查集合是否是另一集合的子集:<=
如果a集合的元素全部在b集合中出现,那么a集合是b集合的子集(b集合就是a集合的超集)。
-
检查集合是否是另一集合的子集:<
如果b集合中含有a集合中的所有元素,且b中还有a中没有的元素,那么b集合是a集合的真超集(a集合就是b集合的真子集)。
-
-
集合的方法
len():获取集合的元素个数。
in:检查集合中是否包含指定的键。
not in:检查集合中是否不包含指定的键。
函数
函数也是对象,可以用来保存一些可执行的代码,在需要时进行多次调用,函数可以嵌套。
函数的操作
-
创建函数
语法: def 函数名(形参1,形参2,..形参n): 代码块
函数名符合标识符的命名规则。
定义的函数一般是用来实现某种功能,函数不会马上执行需要调用。
-
调用函数
语法: 函数名(形参1,形参2,..形参n)
函数可以多次调用。
-
函数的参数
语法: def 函数名(形参1 = 20,形参2): 代码块
定义形参时,可以指定默认值。
定义函数中的参数是形式参数,调用函数时必须传递实际参数,形参和实参的数量一定相等。
参数
-
实际参数的传递方式
-
位置参数
实参对应形参赋值。
-
关键字参数
可以不按照形参顺序,根据参数名传递。
-
-
参数的特性
- 位置参数和关键字参数可以混合使用,但必须将位置参数放前面。
- 函数在调用参数时,解析器不会检查实参的类型,实参可以传递任何类型的对象。
- 注意传递的类型处理要符合规则。
- 函数中对形参进行重新赋值,不影响其他变量;如果形参执行的是一个对象,通过形参修改对象时,影响所有指向该对象的变量。
-
不定长参数
- 参数个数不确定时,可在定义函数时,在形参前加上一个*,这个形参将获取所有的实参并保存到元组中,其他的形参必须使用关键字参数。
- 若在有形参的开头直接写一个*,则要求所有的形参必须以关键字参数得形式传递。
- *形参只能接受位置参数,而不能接收关键字参数,但**形参可以接收其他的关键字参数,并保存为字典。
- **形参只有一个,且必须保存在所有参数的最后。
-
参数解包
- 传递实参时,可以在序列类型的形参前加*,该形参会自动将序列中的元素一次作为参数传递。(要求序列的元数个数必须和形参的个数一致)
- 字典通过**来进行解包,此时,键对应形参,值对应参数传递值。
返回值
函数执行以后返回的结果,通过return 指定函数的返回值。
-
可以通过变量接收
-
可以直接使用函数的返回值
-
返回值可以是任何对象,包括函数
-
没有返回值相当于返回NONE
-
函数中,return后的代码都不会执行
break:退出循环 continue:跳过单词循环 return:结束函数
-
fn和fn()的区别
fn:是函数对象
fn():是调用函数
文档字符串
文档字符串是函数的说明,在函数内部编写。
-
文档字符串:在函数的第一行编写的字符串
-
函数编写了文档字符串,可以通过help()函数来查看说明。
-
help()是python的内置函数,可以查询python的函数用法。
语法: help(函数名)
函数式编程
在python中,函数是一等对象。
一等对象的特点:
- 对象在运行时创建
- 能赋值给变量或作为数据结构中的元素
- 能作为参数传递
- 能作为返回值传递
高阶函数
接收函数作为参数,或将函数作为返回值的函数是高阶函数高阶函数至少要结合以下特点中的一个
-
接收一个或多个函数作为参数
-
将函数作为返回值返回
这种高阶函数也称为闭包,通过闭包可以创建一些只有当前函数能访问的变量,可以将私有数据隐藏到闭包中。
形成闭包的条件
- 函数嵌套
- 将内部函数作为返回值返回
- 内部函数必须要使用到外部函数的变量。
装饰器
需求:函数在计算前打印开始,计算后打印结束。
解决:可以直接修改函数的代码完成需求。
问题:
-
修改函数过多,改起来很麻烦
-
不方便后期维护
-
会违反开闭原则(OCP)
开闭原则:程序的设计,要求开发对程序的拓展,关闭对程序的修改。
要求:不修改原函数的情况下,对函数进行拓展。
上述方法已实现不修改原函数对函数拓展,但需要手动创建新函数,比较麻烦。
为解决该问题,可创建一个可以不修改原函数的情况下,进行拓展的自动生产函数的函数,这个函数就称为装饰器。
- 定义函数时,可以使用@装饰器 来使用指定的装饰器来装饰当前函数
- 可以同时为一个函数指定多个装饰器,装饰器会从内层执行至外层
在开发中,通过装饰器来拓展函数的功能
匿名函数
lambda()函数表达式专门用来创建一些简单的函数,它是函数创建的又一种形式。
语法:
lambda 参数列表:返回值1
用法:
-
(lambda 参数列表:返回值1)(实参)
-
变量名= lambda 参数列表:返回值1
-
变量名= filter(lambda 参数列表:返回值1,…)
匿名函数一般作为参数使用,其他地方一般不会使用。
常用函数
一.input()函数
用来获取用户输入(类型为字符串)
- 调用后,程序立即暂停,等待用户输入
- 输入后,点击回车继续执行程序
- 输入完成后,输入的内容会以返回值的形式返回
- 可以设置一个字符串作为参数,作为提示文字显示
- 也可以用于阻止程序结束
二.len()函数
用来获取序列长度(类型为整数)
- 通过该函数可以获取列表的长度。
- 获得的长度值为最大索引+1。
三.range()函数
用来生成一个自然数序列。
- 可以创建一个执行次数的for循环。
- 需要三个参数(用逗号分隔,包头不包尾)
- 起始位置:可省略,默认为0
- 结束位置
- 步长:可省略,默认为1
四.filter()函数
filter()函数可以从序列中过滤出符合条件的元素,保存到一个新的序列里,要将结果转换成列表打印。
参数
- 函数,根据函数来过滤序列(可迭代的结构)
- 需要过滤的序列(可迭代的结构)
返回值
过滤后的序列
五.map()函数
map()函数可以对迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象返回,要将结果转换成列表打印。
参数
- 函数,根据函数来操作序列(可迭代的结构)
- 需要操作的序列(可迭代的结构)
返回值
操作后的序列
六.sorted()函数
sorted()函数用法和sort()方法基本一致,但sorted()可以对任意序列进行排序不影响原对象,而是返回一个新对象。
方法
一.sort()方法
sort()方法用来对列表中的元素进行排序,默认是直接比较列表中的元素大小。
sort()可以接收一个关键字参数-key
需要一个函数作为参数,每次都以列表的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小。
作用域(scope)
指变量生效的区域。
作用域的分类
- 全局作用域
- 在程序执行时创建,结束时销毁
- 函数以外的区域是全局作用域
- 全局作用域中定义的变量都是全局变量,全局变量可以在任意位置被访问
- 函数作用域
- 在函数调用时创建,结束时销毁
- 函数每调用一次就产生一个新的函数作用域
- 函数作用域中定义的变量都是局部变量,局部变量只能在函数每部访问
- 变量的查找
-
使用变量时,会优先在当前作用域中寻找该变量,有则使用,无则去上一级作用域中寻找,以此类推,若依旧没有找到,抛出异常。
错误:NameError:name ‘a’ is not defined
-
在函数中为变量赋值时,默认是为局部变量赋值。
-
在函数中要修改全局变量,需要用global关键字来声明使用的变量是全局变量,此时修改该变量就是修改该变量的全局变量。
-
命名空间
命名空间指的是变量存储的位置,每个变量都需要存储到指定的命名空间中,每个作用域都有一个它对应的命名空间。命名空间实际上是一个专门存储变量的字典。
- 全局命名空间:保存全局变量。
- 函数命名空间:保存函数中的变量。
- locals()函数:用来获取当前作用域的命名空间,返回值是一个字典。
- globals()函数:用来在任意位置获取全局命名空间,返回值是一个字典。
递归
递归是解决问题的一种方式,和循环很像,可以互相替代。他的整体思想是将一个大问题分解成一个个的小问题,直到问题无法分解时再解决。递归简单理解就是自己调用自己(套娃)。
一.递归的两个要件
-
基线条件
问题可以被分解的最小问题,当满足极限条件时,递归就不执行。
-
递归条件
将问题继续分解的条件。
模块(module)
模块化将一个完整的程序分解成一个一个的小模块,通过模块组合搭建一个完整的程序,通过模块可以对python进行拓展。
模块化:将所有代码写到一个文件中
非模块化:将程序分别编写到多个文件中
python中一个py文件就是一个模块。
模块名符合符号标识符的规范
引入模块
import可以在程序的任意位置调用,但一般情况下,会统一写在程序的开头。
每个模块内部都有一个__name__属性,通过这个属性可以获取模块的名字。
__name__属性值为__main__的模块是主模块,一个程序只有一个主模块,是直接执行的模块。
引入整个模块
语法:
import 模块名
或
from 模块名 import * #一般不使用
或
import 模块名 as 别名
使用 import * 引入时,不会引入_开头的变量,格式为_变量名的变量只能在模块内部访问
引入部分模块
语法:
from 模块名 import 变量(,变量2...)
或
from 模块名 import 变量 as 别名
一个模块可以引入多次,但模块的实例只创建一个
模块测试
模块测试时需要执行,但调用模块后不用执行的测试代码,可以判断当前模块是否是主模块来实现。
语法:
if __name__ == '__main__':
代码块
使用模块
模块可以定义变量,函数和类,被引入后,可以在主模块直接使用。
访问模块的变量
语法:
模块名.变量名
访问模块的函数
语法:
模块名.函数名()
模块化的优点
- 方便开发
- 方便维护
- 可以复用
包(package)
包也是模块,当模块中代码过多或一个模块需要分为多个模块时,就需要用到包。
包是一个文件夹,每个包中必须要有一个个的__init__.py文件,该文件可以包含包中的主要内容。
使用包会产生一个__pycache__文件夹,这个文件是模块的缓存文件,为了提高程序运行的性能将模块的代码先转换成机器码再交给计算机执行(编译一次后),下次使用可以直接使用缓存中编译好的代码。
引入包
语法:
import 文件夹名
引入包中其他模块
语法:
from 文件夹名 import 模块名
使用包中的变量,函数和类,用法同模块一致。
一.time
统计程序执行时间。
- time()函数:获取当前的时间,单位为秒
面向对象(oop)
python是一门面向对象的语言。所谓的面相对象的语言,可理解为是中的所有操作都是通过对象来进行的。
面向过程的编程语言
面向过程的编程思想是将程序的逻辑分解为一个一个的步骤,通过对每个步骤的抽象来完成程序。
面向过程的编写方式只适用于一个功能,符合人类的思维,编写相对简单,但可复用性比较低,难于维护。
面向对象的编程语言
面向对象的编程语言,关注的是对象而不是过程,对于面向对象的语言来说,一切皆对象。
面向对象的编程思想将所有的功能统一保存到对象中。面向对象的编写方式不太符合常规的思维,但比较容易阅读且易于维护,容易复用。
面向对象的三大特征
-
封装
确保对象的数据安全
-
继承
保证了对象的可拓展性
-
多态
保证了程序的灵活性
类(class)
之前学习的对象都是内置的对象,但是内置对象不能满足所有的需求,在开发时,需要自定义对象。
类可理解为对象的图纸,称对象是类的实例(instance),在程序中需要根据类来创建对象。
如果多个对象是通过一个类创建,则称这些对象是一类对象。
自定义的类都需要大写字母开头,使用大驼峰命名法(帕斯卡命名法)对类进行命名。
类是type类型的对象,定义类实际上是定义一个type类型的对象。
int(),float(),bool(),str(),list(),dict()…都是类
定义类
使用class关键字来定义类,语法与函数类似。
语法:
class 类名([父类]):
代码块
类也是一个对象,类是一个可以创建对象的对象!
使用类创建对象的流程
- 创建一个变量
- 在内存中创建一个新的对象
- 将对象的id赋值给变量
使用类的操作
-
创建类的实例
语法:
对象名 = 类名()
-
isinstance():可以使用isinstance()来检查一个对象是否是一个类的实例。
语法:
isinstance(对象名,类名)
-
向对象添加变量,对象中的变量称为属性。
语法:
对象名.属性名=值
可以使用这种方法修改属性的值,但信息不安全,因为修改不论对错。
类的定义
类和对象是对现实生活的事物或程序中的内容的抽象。
实际上所有的事物都由两部分组成:
- 数据(属性)
- 行为(方法)
可以在类里定义变量和函数:
-
类里的变量将会成为所有实例的公共属性,即所有实例都可以访问。
-
类中的函数称为方法,这些方法可以通过该类的所有实例来访问。
调用方法
语法: 对象.方法名()
方法调用和函数调用的区别
函数调用:调用时有几个参数就有几个实参。
方法调用:默认传递一个参数,所以方法中至少要定义一个形参。
方法每次调用时,解析器都会自动传递第一个实参。第一个实参就是调用方法的对象本身,一般把这个参数命名为self。
类中的属性和方法
类属性是直接在类中定义的属性,可以通过类或类的实例访问,但是类属性只能通过类对象修改,无法通过实例对象修改。
实例属性是同归实例对象添加的属性,但是实例属性只能通过实例对象访问和修改,无法通过类对象修改。
实例方法是在类中定义,以self为第一个参数的方法,可以通过实例和类调用,在实例调用时会将当前调用对象作为self传入,在类调用时不会传递self,必须手动传递。
类方法是在类内部使用装饰器 @classmethod 来修饰的方法,第一个参数是cls,是当前的类对象会被自动传递,可以通过实例和类调用。
类方法和实例方法的区别:类方法的第一个参数是cls,实例方法的第一个参数是self
静态方法是在类中使用装饰器 @staticmethod 来修饰的方法,可以通过类和实例调用,不需要指定任何的默认参数,静态方法一般是一些工具方法,基本跟当前类无关,只是保存到类中的函数。
属性和方法的查找流程
调用一个对象属性时,先在对象中查找该属性,若存在就返回属性值,若不存在就在类中查找,找到就返回值,若都不存在,则报错。
类对象和实例对象中可以保存属性(方法)
如果这个属性是所有的实例共享的,应该将其保存在类对象中。
如果这个属性是实例特有的,应该保存在市里对象中。
方法中不能直接访问类的属性。
特殊方法
特殊方法也称为魔术方法。
特殊方法的特性
- 类中可以定义特殊方法,特殊方法是以__开头,__结束。
- 特殊方法不需要调用。
- 特殊方法在特殊时候自动调用。
开发中要了解特殊方法
- 特殊方法什么时候调用
- 特殊方法的作用
-
init
语法: def __init__(): pass
init方法会在对象创建后立刻执行,可以用来向新创建的对象中初始化属性。
调用类创建对象时,类后边的所有参数会依次传递到init()中。
-
str
语法: def __str__(): pass
这个特殊方法会在尝试将对象转换为字符串是调用,作用是用来指定对象转换字符串的结果。
打印一个对象是实际上就是打印对象中的特殊方法__str__的返回值(print)
-
repr
语法: def __repr__(): pass
这个特殊方法对当前对象使用repr()函数是调用,作用是用来指定对象在"交互模式"中直接输出的结果。
打印一个对象是实际上就是打印对象中的特殊方法__str__的返回值
其他特殊方法可以自行搜索!
封装
封装指的是隐藏对象中的一些不希望被外部访问到的属性或方法,是面向对象的三大特性之一。
使用封装会增加类的定义的复杂程度,但也确保了数据的安全性。
- 隐藏属性名,用户无法随意修改对象中的属性。
- 增加getter和setter方法,控制属性是否可读和修改。
- 属性只读则删除setter方法,属性不可读则删除getter方法。
- getter方法设置属性可以增加数据验证,确保数据的准确性。
- getter方法和setter方法可以在读取和修改属性时做一些其他处理。
- getter方法可以表示一些计算的类型。
如何隐藏对象中的属性:
- 将对象的属性名修改为一个不为外部知道的名字。(假装隐藏,实际没有)
- 可以在隐藏的对象属性开头使用双下划线(__xxx),双下划线开头的属性是对象的隐藏属性,隐藏属性只能在内部访问,不能通过对象访问。(假装隐藏,还能通过外部访问和修改,实际上是python为隐藏属性自动修改名字,改为了._类名__属性名,不建议使用)
- 一般会将私有属性以_类开头,没有特殊需要不要修改私有属性(依然可以修改,但常用这种方法设置私有属性)
如何获取(修改)对象的属性:
- 需要提供一个getter和setter方法是外部可以访问到属性
-
getter:获取对象中的指定属性——get_属性名
语法: def get_属性名(self,属性名): return self.内部属性名
-
setter:用来设置对象的指定属性——set_属性名
语法: def get_属性名(self,属性名): self.内部属性名=属性名
-
property装饰器
用来将get方法转换为对象的属性,使用后可以像调用属性一样使用get方法.
property装饰器的特性
- 方法名必须要与属性名一致。
- 使用后如没有定义setter方法则不能修改
语法:
@property
def 属性名(self,属性名):
return self.内部属性名
print(对象.属性名)
使用property装饰器后,也需要为setter方法设置装饰器-@属性名.setter
语法:
@属性名.setter
def 属性名(self,属性名):
self.内部属性名 = 属性名
对象.属性名 = 值
getter方法是必须的!
有一个类可以实现部分功能,若要它实现全部功能,可进行如下操作:
- 直接修改这个类,在类中添加所需功能,但比较麻烦,会违反oop原则。
- 直接创建一个新类,但也比较麻烦,会出现大量重复性代码。
- 直接从这个类继承属性和方法,子类(衍生类)可以继承父类所有的属性和方法。
定义类名是可以在类名后的括号中指定当前类的父类(超类、基类、supper)。
语法:
class 类名([父类]):
代码块
可以使用issubclass()来检查一个类是否是另一个类的子类。
语法:
issubclass(父类,子类)
在创建类时,如果省略父类,则默认父类为Object。Object是所有类的父类。
继承
继承可以使一个类获取到其他类中的属性和方法,是面向对象的三大特性之一,通过继承避免了编写重复代码且符合ooc原则,所以经常使用继承对一个类进行拓展。
方法的重写
如果字类中有和父类同名的方法,则通过子类实例去调用方法时,会调用子类的方法而不是父类的方法,这个特点称为方法的重写(override)。
调用方法的优先级
优先在当前对象中寻找是否有该方法,有则调用,无则到当前对象的父类寻找,若父类有就调用,无则到父类的父类中寻找,以此类推。
直到找到oblect为止,若还是没找到,就报错!
重写特殊方法
父类中的所有方法都会被子类继承,包括特殊方法,特殊方法可以重写。
调用父类的__init__来初始化父类中定义的属性。
- 直接调用父类的__init__
语法:
父类.__init__(self,属性...)
- 使用super()方法可以获取当前类的父类,使用该方法调用父类方法时,不需要传递self。
语法:
super().__init__(属性...)
多重继承
可以在类名的后边添加多个类来实现多重继承。
语法:
class 子类(父类1,父类2...)
如果父类中有同名的方法,会按照顺序依次在父类(父类的父类找不到后再在子类的下一个父类寻找)中寻找。
找过的父类不重复寻找,若都找不到可用方法就报错!
可以用__bases__属性来获取当前类的所有父类。
语法:
子类.__bases__
python支持多重继承,即可以为一个类同时制定多个父类,可以使子类同时拥有多个父类,并且会获取到所有父类中的方法。
开发中没有特殊情况时,应尽量避免使用多重继承,因为多重继承会让代码过于复杂!
多态
多态指一个对象可以以不同形态呈现,是面向对象的三大特性之一。
在函数中,只要对象中含有函数要使用的属性,就可以作为参数传递,这个函数不会考虑对象的类型,这个就叫多态。
如果在函数中使用类型检查isinstance(),那么除被检查的类型,其他类型都无法使用该函数,那么这个函数就违反了多态,这样的函数无法处理其它类型的对象,导致函数的适应性非常差。
鸭子类型:如果一个东西,走路像鸭子,叫声像鸭子,那么它就是鸭子!
以len()方法为例:
对象可以通过len()方法获取长度,是因为对象中有一个特殊方法__len__。
垃圾回收
程序在运行过程中会产生垃圾,这些垃圾会影响程序的性能,所以必须及时清理。
程序中没有被引用的就是垃圾,垃圾回收就是将垃圾对象从内存中删除。
python中有垃圾回收机制,会自动将没有被引用的对象删除。
类中有 del 特殊方法,在对象被垃圾回收前调用。
将实例对象设置为None,若没有变量对类进行引用,就变成了垃圾。
python标准库
核心思想:开箱即用,python提供了模块标准库,随python的安装一同安装,可以直接调用。
-
sys模块
提供一些变量和函数,可以获取python解析器的信息,也可以通过函数操作python解析器。
- sys.argv:该属性是一个列表,获取执行代码时,命令行中包含的参数。
- sys.modules:该属性是一个字典,字典的key是模块的名字,字典的value是模块对象,获取当前程序中引入的所有模块。
- sys.path:该属性是一个列表,列表保存了模块的搜索路径。
- sys.platform:返回当前的运行平台。
- sys.exit():用来退出程序。
-
os模块
可以对操作系统进行访问。
- os.environ:可以获取系统的环境变量。
- os.system():可以执行操作系统的命令。
-
pprint模块
提供一个方法—pretty print。
pprint():该方法可以用来对打印的数据做简单的格式化。
异常
程序在运行时,不可避免会出现一些错误,就称为异常。如:使用没有赋值的变量,使用不存在的索引,除0等等。
异常会导致程序立即终止,异常后的程序不会执行。
处理异常
程序出现异常目的不是让程序直接终止,是希望异常出现时有代码进行处理。
可以将可能出现错误的代码放入try语句,若无错误则正常执行,若错误,则执行except子句的代码来处理异常,避免因为一个异常导致程序的终止。(except可以重复使用)
语句:
try:
代码块 #可能出现错误的代码
except (异常类型):
代码块 #出错后的处理方法
else:
代码块 #没出错时执行的代码
异常传播(抛出异常)
当在函数中出现异常时,若在函数中对异常进行了处理,则异常不会继续传播,若函数中没有对异常进行处理,则异常会继续向函数调用出传播,直到传递到全局作用域(主模块)依然没有处理,则程序终止并显示异常信息。
当程序运行过程中出现异常,所有的异常信息会被保存在中专门的异常对象中,异常传播时,实际上就是异常对象抛给了调用处。
当出现错误时,就会创建对应错误的类的实例。例如:ZeroDivisionError类表示除0的异常,NameError类用来处理变量的错误异常等。
异常对象
except后不跟任何内容,则会捕获所有异常,若except后跟具体的异常类型,则只捕获该异常类型的异常。
Exception是所有异常的父类,如果except 后跟的是Exception也会捕获所有的异常。
语句:
try:
代码块 #可能出现错误的代码
except Exception as 变量名:#变量名实际上是异常对象
代码块 #出错后的处理方法
else:
代码块 #没出错时执行的代码
finally:
代码块 #无论有无异常总会执行
try语句必须要有,else可有可无,except和finally必有其一
自定义异常
创建一个类继承Exception就可以自定义异常类。
抛出异常的目的是告知调用者函数调用时出项问题,希望可以处理。
raise用于向外部抛出异常,后跟一个异常类或异常类的实例。
也可以通过if-else来代替异常处理。
语句:
raise Exception(异常信息)
文件(file)
读取模式:
- t - 默认值,文本文件
- b - 二进制文件
除文本外的文件都称为二进制文件。
文本文件
通过python来对计算机中的各种文件进行增删查改操作。
操作文件的步骤:
-
打开文件
python文件的第一行encoding会被解析为设置编码。
语法: open(file,mode='w',buffering=-1,encoding_=None,errors=None,newline=None,closefd=True,opener=None
file:文件名字(路径)
encoding:编码打开方式,默认为None。
open方法默认打开纯文本。
使用open打开文件时必须指定打开文件所要执行的操作,不指定就默认读(rt)。
使用写和添加操作时,如果文件不存在,则创建文件并写入,如果存在则覆盖原有的文本信息。
使用新建时,如果文件不存在则新建,存在则报错。
操作有读-r、写-w、添加-a、新建-x、可读写-r+、w+、a+。可读写的操作若文件不存在,会报错。
在同一文件夹可以使用相对路径,不在同一文件夹要使用绝对路径。
返回值:返回一个对象,这个对象代表当前打开的文件。
在使用路径时,windows可以使用/代替\或使用\,或可以使用原始字符串(引号前+r)
-
对文件进行操作
读取
-
read():读取文件的内容,用于utf-8等编码编写的文本文件,将内容保存作为字符串返回。如果文件较大会一次性将内容加载到内存,容易导致内存泄露。
可以接受一个size参数,用来指定要读取的字符数量,每次都从上次读到的位置继续读取,默认值为-1,即读取所有字符。
若读取二进制文件时,size参数用来指定读取文件的字节数,不要一次性读取。
大文件不宜一次读完,可使用size指定每次读取的字符
-
readline():按行读取文件的内容。
-
readlines():用于按行读取文件内容,但是一次性读取到列表返回。
写入
- write():向文件写入内容,需要传递一个字符串作为参数,可以多次执行写入内容 ,写入完成后返回写入的字符个数。
-
-
关闭文件
-
close():调用该方法来关闭文件。
-
with…as语句
语法: with open(文件名) as 变量名: print(变量名.read())
变量名是文件对象
在with语句中可以直接使用文件对象做文件操作,该文件只能在with语句中使用,一旦语句结束,文件会自动执行close()
-
-
方法
以下方法的参数需要根据字节数操作。
- tell():查看当前的读取位置。
- seek():改变当前的读取位置,需要两个参数,一是要切换的位置,二是计算位置的方法,默认为0,从0开始计算;1,从当前位置开始计算;2从末尾开始计算。