python基础
一、数值类型与序列类型
知识点:
1.变量与定义 2.数值类型数据 3.序列类型数据 4.序列类型的通用操作
1.数值类型
变量与定义:
1、什么是变量?
变量就是用来储存数据的
2、变量怎么定义?
a = 123
3、变量的命名规则: myVar my_var
变量命名、:数字、字母、下划线,并且不能以数字开头,不要用关键字命名
查看关键字:import keyword
keywrod.kwlist (了解即可)
数值类型
1、什么是数值类型数据呢?
2、Python中总共有多少数值类型?
int :整数
float:浮点数
complex:复数
bool:布尔型 (特殊的数值类型,只有True和False两个值)
3、怎么查看数据的类型呢?——> type( )
a = 123
print(type(a))
一、数值的基本运算
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | 两个对象相加 a + b 输出的结果 |
- | 减 | 得到负数 或 一个数减另一个数 a - b 输出结果 -10 |
* | 乘 | 两个数相乘 或 返回重复若干次的字符串 a * b 输出的结果 |
/ | 除 | x 除以 y , b / a 输出的结果 |
二、Python中其他运算方法
运算符 | 描述 | 实例 |
---|---|---|
// | 取整除 | 返回商的整数部分 9 // 2 输出的结果 4.0 |
% | 取余 | 返回除法的余数 10 % 5 得结果 0 |
** | 幂次方 | 返回x的y幂次方 5 **2 的 5的2次方,输出的结果 25 |
1、Python里面小数如何进行精确计算(了解即可)
# 如果进行精确计算? 导入 decimal模块
improt decimal
b = decimal.Decimal('2')
a = decimal.Decimal('2.3')
c = a - b
print( c )
2、Python中 //运算 默认运算向下取 整数
(1): 向下取 整数
a = 5 // 2
print( a )
(2):如果要向上取整的话,需要导入模块math
import math
a = 8/3
b = math.ceil( a )
print(b)
如何应用
1.数值计算: 常见的数值计算
2.布尔型: 在后面要学习到的判断中,是根据布尔值来判断是否执行
3.四则运算: 能够灵活的使用四则运算往往可以很大程度上精简我们的代码
数值类型总结:
整型、浮点数和布尔型的定义和使用必须要掌握
复数和decimal(定点数)了解即可
熟练使用常见的算术运算符
了解math模块,需要的时候查看看文档
2.序列类型
思考?
在Python中如果我想表示字母怎么办呢?
在Python中有东西既可以放字符串又可以放数值吗?
序列类型数据有哪些?
一、字符串:str (字符串定义:用引号包起来)
a = 'hackers123'
二、列表:list ( 列表的定义:中括号 [ ] )
a = [1,2,3]
三、元组 :tuple ( 元祖的定义:小括号() )
b = ( 1,2,'abc' )
序列类型的通用操作?
一、索引取值和切片
二、序列类型之间相互转换
三、变量引用和拆包
一、下标索引取值和切片
一、索引取值
a = (1,2,3,4,5,'abc')
b = a[0]
print( b )
二、序列类型的切片
a = (,1,2,3,4,5,6)
b = a[1:4]
print(b)
二、Python的序列类型的相互转换
思考?
不同的序列类型可以相互转化吗?
列表和元组有什么区别呢?
扩展知识点
一、变量的重新赋值
二、变量的引用
三、拆包
二、序列类型的方法
本节知识点
1. 列表方法
2. 字符串方法
3. 元组的方法
1.列表方法
思考?
我们之前知道列表取值的方法,那怎么对数据做增删改查呢?
列表除了增删改查还有什么其他的方法呢?
列表方法
1、增:
append() (添加单个元素)
insert() (指定位置插入元素)
extend() (添加多个元素)
eg:
li = [1,2,3,4,5,6]
li.append(10)
print(li) # 1,2,3,4,5,6,10
2、查:
index() (查找元素下标)
count() (查找元素出现的个数)
eg:
li = [1,2,3,4,5,6]
index = li.index(2)
print( index ) # 3
3、删:
pop() (删除一个元素)
remove() (删除指定元素)
clear() (情况列表)
eg:
li = [1,2,3,4,5,6]
index = li.remove(6)
print( index ) # 返回已删除的元素: 6
4、改: 通过下标改值
eg:
a = [1,5,6]
a[0] = 4
print(a) # 4,5,6
5、其他方法:
copy() : (复制 )
reverse(): (反向)
sort(): (排序)
eg:
li = [1,2,3,4,5,6]
num = li.reverse()
print( num ) # [6,5,4,3,2,1]
列表的应用
1.列表是python中最基本也是使用十分广泛的数据类型
2.列表的使用在Python代码几乎无处不在
3.因此同学们对列表的增删改查操作需要十分熟悉,并且要知道同种类型
不同方法之间的区别
2.字符串方法
思考?
字符串可以增删改吗?
如果可以的话那要怎样做呢?
字符串方法
count():查看元素出现的次数
eg:
s = '123cdsff'
num = s.count('f')
print(num) # 次数为2
find():查找元素是否存在(存在返回下标,不存在返回-1)
eg:
s = '123cdsff'
num = s.find('2')
print(num) # 下标为:1
index():跟find一样,不存在报错(存在返回下标,不存在报错)
eg:
s = '123cdsff'
num = s.find('2')
print(num) # 下标为:1
split():分割(通过指定元素作为分割点,将字符串分割,也可添加参数指定分割次数)
eg:
s = '123cdsff'
ss = s.split('c')
print(ss) # ['123',,'',dsff']
replace():替换(将指定元素全部替换)
eg:
s = '123cdsff'
ss = s.replace('c','a')
print(ss) # '123adsff'
字符串方法(了解即可)
isdigit:查看字符串是否是纯数字
isalpha:查看字符串是否是纯字母
endswith:查看字符串是否已指定字段结束
startswith:查看字符串是否已指定字符开头
islower:查看是否包含字母,并且字母都是小写
isupper:查看是否包含字母,并且字母都是大写
upper:把字符串中的小写自怒转化为大写
lower:把字符串中的大小写字母转化为小写
capitalize:把字符串第一个字母大写
title:把每个单词首字母大写
strip :删除两端空白字符
lstrip:删除左边空白字符
rstrip:删除右边空白字符
语法格式( 字符串.方法名() ):
str1 = '12345'
print( str1.isdigit() ) # True
字符串拼接
1、使用 +
str1 + str2 + str3
2、格式化字符串
’%s %%s’%(str1,str2,str3)
3、使用join
’’.join([str1, str2, str3])
4、使用 format
’{} {} {}’.format(obj1,obj2,obj3)
’{0} {1} {2}’.format(obj1,obj2,obj3)
'{n0} {n1} {n2}'.format(n1=obj1,n0=obj2,n2=obj3)
字符串的应用
1.字符串方法:
字符串方法可以方便的对字符串作出处理,虽然字符串是不可变对象,但是可以通过返回新对象的方法来实 现增删改查,字符串方法很多,掌握常用的就好
2.字符串拼接和格式化
实际中我们会将很多的字符串拼接起来,然后输出或者是传输,这就需要我们能够熟练的使用拼接和格式化 方法,在不同的场景中选择方便和合适的方法
3.字符串的转义
字符串的转义能表示很多不方便显示的字符,但同时也会带来一些麻烦,要学会正确的处理
3.元组的方法
思考?
元组有哪些方法呢?
元组方法:
查询元素出现次数: count()
查看元素第一个出现的位置: index()
元组的应用
元组是不可变对象,如果需要改变,转化成列表即可
元组中只有 count 和 index 方法,方便查找元组中的数据
三、使用 Vim 编辑 python
本节知识点
01. Linux常用命令
02. vim使用
03. vim编辑py文件
04. input、print
Linux常用命令
1. 查看文件信息:ls
2. 显示当前路径:pwd
3. 创建目录:mkdir
4.创建文件:touch
5.切换工作路径:cd
命令 | 含义 |
---|---|
cd | 切换到当前用户的主目录(/home/用户目录),用户登录的时候,默认的目录就是用户的主目录 |
cd ~ | 切换到当前用户的主目录(/home/用户目录) |
cd . | 切换到当前目录 |
cd .. | 切换到上级目录 |
cd - | 可静茹上次所在的目录 |
Linux命令
删除目录:rmdir (必须是空目录)
删除文件:rm
参数 含义
-i 以进入交互方式执行
-f 强制删除,忽略不存在的文件,无需提示
-r 递归地删除目录下的内容,删除文件夹时必须加此参数
输出重定向命令:>
查看文件内容及合并文件:cat
复制文件:cp
移动文件:mv
清屏:clear
查看当前用户:whoami
查看日历:cal
查看当前时间:date
查看进程信息:ps
动态显示进程:top
远程测试主机连通性 : ping
查看网卡信息 : ifconfig
重启: reboot
关机:(poweroff shutdown init)
获取root权限 : sudo
Vim介绍
编辑器:
Vim是Linux上常用编辑器,在Windows上可以使用记事本来编辑文件内容,Vim也类似于记事本,但是 Vim有更加强大的功能,这样Vim长久不衰
三种模式:
在Vim中,有命令模式,输入模式 和 末行模式三种模式。
按 Esc 进入命令模式
输入 Shift + ; 进入末行模式
输入插入命令,如(i,a,o) 进入shu ru模式
Vim插件:
Vim丰富的插件,可以把Vim打造成一个功能完备的IDE,我们提供给大家的Vim已经配置成一个适用于 Python开发的IDE
Vim使用
一、进入
vim 文件名
退出
:wq 末行模式,wq 保存退出
:q 末行模式,q 直接退出
:q! 末行模式,q! 强制退出,不保存
二、输入模式
i 从光标所在位置前面开始插入
I 在当前行首插入
a 从光标所在位置后面开始输入
A 在当前行尾插入
o 在光标所在行下方新增一行并进入输入模式
O 在当前上面一行插入
# 进入输入模式后,在最后一行会出现--INSERT—的字样
三、移动光标
gg 到文件第一行
G 到文件最后一行 (Shift + g)
^ 非空格行首
0 行首(数字0)
$ 行尾
四、复制和粘贴
yy 复制整行内容
3yy 复制3行内容
yw 复制当前光标到单词尾内容
p 粘贴
五、块操作:
v 块选择
ctrl + v 列块选择
六、删除
dd 删除光标所在行
dw 删除一个单词
x 删除光标所在字符
u 撤销上一次操作
s 替换
ctrl + r 撤销 u
七、查找
/ 命令模式下输入:/ 向前搜索
? 命令模式下输入:? 向后搜索
n 向下查找
N 向上查找
Vim编辑py文件
在Linux中,文件后缀只是一个标示, 任何文件都
可以用vim打开,py文件也是,也可以用vim文件
打开编辑
思考?
如果是写在py文件中的python代码要怎么运行呢?
py文件的的运行
一、
退出Vim,再执行
python file.py
二、
如果是使用的我们提供给大家的Vim,可以按 F5 运行
注意:F5运行只是方便大家在学习过程中,方便大家调
试代码而配置的,在实际项目中,还是使用第一种方法
运行python程序
python虚拟环境的使用
查看已经安装的虚拟环境
workon
进入虚拟环境:
workon 虚拟环境名
退出虚拟环境,家目录下执行:
deactivate
输入 | 输出
输入:input()
输出:print()
四、格式化输出 和 深浅复制
本节知识点
01. 格式化输出和字符串转义
02. 字符串编码
03. bytes和bytearray
04. 深浅复制
1.格式化输出和字符串转义
思考?
什么是格式化输出,之前讲了字符串的拼接就已经用到过了,其中用到的%s就是格式化输出的一种,除了%s还有哪些格式化?
format还有其他的用法吗?
格式化输出—>传统方法
%s:通过str() 字符串转换来格式化
了解:
%d %数字
%f %浮点数
%c %ASCII字符
%o %8进制
%x %16进制
%e %科学计数法
‘%-6.3f’%10.3 左对齐
‘%+-6.3f’%10.3 显示正负
‘%5s’%’ab’ 格式化长度
掌握:
print(‘%s’%’123’)
print(‘%r’%’123’)
Python方法
format
了解:
'{:.2f}'.format(12.333) 保留小数点后两位
'{a:.2f}'.format(a=12.333)
'{:.2%}'.format(0.333) 百分比格式
'{0:x}'.format(20) 转换成十六进制
'{0:o}'.format(20) 转换成八进制
进制转换的时候用{0:进制}
'{:0<10}'.format(12.3) 右对齐,长度为10
'{:x<10}'.format(13.44) 数字补x
'{:0>10}'.format(13.44) 左对齐...
'{:0^10}'.format(13.44) 两边对齐...
'{{ hello {0} }}'.format('python’) 转义{和}符号
f = ' hello {0} '.format
f('python’) 这里可以把format当作一个函数来看
字符串的转义
字符前面加上 \ ,字符就不再表示字符本身的意思,表示ASCII码中不能显示字符,
常见有下:
\n 换行
\t 水平制表符
\b 退格
\r 回车,当前位置移到本行开头
\\ 代表反斜杠 \
\’ 代表一个单引号,同样的 “ ? 等符号也可以这么输出
\0 代表一个空字符
\a 系统提示音
在python中如果要去掉字符串的转义,只需要在字符串前面加上 r
r'abc\tabc'
格式化和转义应用
格式化得到的结果都是字符串,通过把位置预先留出来,
后期再往其中填入内容可以让输出内容更加整洁美观,而又具有良好的可读性,同时让代码更简洁精练
字符串的转义可以方便我们表示我们不太方便表示的字符,同时转义有些情况下又会带来麻烦,特别是在表示路径的时候,这种情况下可以在字符串前面加上 r 来去掉字符串的转义
2.字符串编码
思考
刚才我们讲到了我们在python内部要对字符串进行拼接和格式化是为了输出和传输,那python中字符串的可以直接在网络上传输吗?
如果不可以的话,python内部是怎么做的呢?
编 码
'编码数据'.encode(encoding='utf8')
'编码数据'.encode(encoding='gbk')
上面的输出结果分别是:
b'\xe6\xbd\xad\xe5\xb7\x9e'
b'\xcc\xb6\xd6\xdd'
字符串编码的作用
Python统一了编码,这样Python在内部处理的时候不会因编码不同而出现程序不能正常执行的问题
Python会自动根据系统环境选择编码,但是经常在文件传输的过程中,会遇到各种不同的编码,这个时候就需要我们去处理编码问题
3.bytes和bytearray
思考
Python中的序列类型还有吗?
bytes二进制序列类型
指定长度的零填充字节对象:
方法:bytes()
eg:
a = bytes(3)
print(a) # b'\x00\x00\x00
二进制字符串对象:
方法:bytes()
eg:
a = bytes(a'abc')
print(a) # b'abc'
bytearray二进制数组
指定长度的零填充字节对象:
方法:bytearray()
二进制字符串对象:
方法:bytearray()
二进制序列类型的应用
二进制序列类型的用法比较少见,是python中少用的一种序列类型
对于二进制序列类型,大家基本了解即可
4.深浅复制
思考
列表里面可以放列表吗?
定义如下列表:
li = [1, 2, 3]
li2 = [‘a’, li]
浅复制:
li3 = li2.copy()
深复制:
import copy
l4 = copy.deepcopy(li2)
深浅复制的应用
深浅复制只有在列表嵌套列表的情况下讨论
如果想保留修改之前的数据,就可以使用列表的复制,但要注意列表嵌套情况下的问题
五、散列类型与 运算符优先级, 逻辑运算
本节知识点
01. 集合
02. 字典
03. 运算符优先级
04. 逻辑运算
1.集合
思考
回想下,列表中可以插入重复的元素吗?
集 合
两种定义方法:
set1 = set(1,2,3)
{1,2,3,4}
三种运算:
s1 & s2 交集
s1 | s2 并集
s1 - s2 差集
集合的增删改查方法
增:
add():增加一个元素
update():将一个集合的所有元素添加到原来集合中
删:
pop(): 删除任意一个元素
remove(): 删除指定元素
查:
isdisjoint() 有交集返回False
issubset() 判断是否包含于
issuperset() 判断是否包含
集合特性
唯一性:集合中的元素具有唯一性,不存在两个相同的元素
无序性:集合中的元素是无序的,所以没有存在索引
可变性:集合是可变对象
2.字典
思考
那么接下来我们开始学习字典,在学习字典之前我们来思考一个问题,如果说我用列表储存了咱们班一个的学员信息,姓名,年龄,电话号码,储存完之后发现电话号码写错了,这个时候要修改电话号码,怎么修改呢?
如果不能确定下标呢?我们怎么改?是不是要先找到下标,然后再修改。那么有没有一种数据类型,可以快速找到我们储存的某个数据呢
字典
两种定义方法
dict1 = {‘name’: '凯华', 'age':18} 键值对形式
dict2 = dict(name='小明', age=18) 使用dict函数
修改和添加:
dict1[‘name’] = '键值'
dict2[‘age’] = 20
字典的增删改查
删:
pop(): 通过keyj键删除对应value键值,并返回
popitem(): 删除一个键值对,并返回
clear(): 清空列表
查:
get(): 通过key查找对应的value志
keys(): 查找出列表内所有的key
values(): 查询所有的value
items(): 显示所有的键值对
增 :
update(): 把一个字典里的键值对添加的原来的字典里
setdefault(): 有则查,无则增
其他方法:
copy(): 复制
fromkeys(): 返回一个新的字典
字典特性
键(key)唯一性:字典中的键(key)具有唯一性,不存在两个相同的键(key)
无序性:字典中的键也是无序的,所以不能通过索引取值
可变性:字典是可变对象,但是字典的键(key)必须是不可变对象
3.运算符优先级
思考
Python中有哪些运算符?
Python中的运算符
运算符 描述
** 幂运算
+、- 一元运算(正负号)
*、/、% 算术运算符
+、-
<、>、<=、>= 比较运算符
==、!=
=、%=、/=、-=、+=、*=、**= 赋值运算符
is、is not 身份运算符
in、not in 成员运算符
not > and > or 逻辑运算符
4.逻辑运算
思考?
如何判断两个对象相同呢?
如何表示多个相同的条件呢?
逻辑运算符
1、查看对象类型:
type
isinstance
2、比较运算符:
==
!=
3、如果有多个条件:
判断语句1 and 判断语句2
判断语句1 or 判断语句2
not 判断语句1
六、控制流程
本节知识点
01. 条件判断
02. 三目运算
03. 条件循环
04. 迭代循环
1.条件判断
思考
py文件中的代码是按照怎样的顺序执行的呢?怎么去验证呢?
代码的执行顺序可以改变吗?如果可以要怎么改变呢?
代码运行顺序
从 上 往 下 依 次 执 行
条件语句
语法结构:
if 判断语句1:
执行语句1
elif 判断语句2:
执行语句2
...
else:
执行语句
2.三目运算
思考:
有这样一个判断,如果值大于5返回True,否则返回False,代码该么写?
有更加简单点的方式吗?
三目运算
一般判断运算:
a = 3
if a > 5:
print(True)
else:
print(False)
三目运算:
a = 3
True if a>5 else False
三目运算格式:
条件满足的结果 if 条件 else 条件不满足的结果
3.条件循环
思考
如果在程序中,在特定的条件下,需要重复做一件事 应该怎么做呢,比如说我们要在屏幕上打印100遍 hello python
我们前面的程序运行一遍接就结束了,有什么办法让前面的程序一直运行
条件循环:while
语法规则:
while 判断语句:
循环体
⚠️ 注意缩进
循环里的 break 和continue 和else
1、break的用法:直接终止循环
2、continue的用法:中止当前这一轮循环,进入下一轮循环
3、else:是在while的条件不成立是执行,循环被break终止的情况下,不会执行else中的内容
条件循环:while
while True:(表示条件始终成立)
while的应用
控制程序流程: 对于不同的条件,执行不同的代码
break: 可以在没有终止条件的情况下结束循环
else: 只有在循环被终止条件终止的情况下才会执行
4.迭代循环
思考
有一个列表li = [1,5,6,8,9,3,2]
如果要把里面的元素,一个一个全部拿出来应该怎么做?
要求打印出1-20内的整数
for 迭代循环
语法规则:
for i in obj:
循环体
案例:
li = [1, 5, 6, 9, 3, 2]
for i in li:
print(i)
注意的要点:
1、for 后面需要接上可迭代对象
2、for会依次取出可迭代对象中的元素
3. 注意缩进
range的用法
range的用法:
for i in range(21):
print(i)
注意的要点:
for循环中也可以用 break continue 和else
end = '' 表示下一次打印不换行
print('xxxx',end='')
for的应用
控制程序流程: 对于不同的条件,执行不同的代码
continue: 可以跳过本次循环,进入下次循环
else: 只有在正常迭代结束,即不是被break终止的情况
七、函数 与 参数
本节知识点
01. 函数的定义和调用
02. 函数参数和返回值
03.常见内置函数
1.函数的定义和调用
思考
问题:有多个地方需要打印怎么做呢
问题:是不是需要打印的地方写重复的代码
函数的定义及调用
1、函数的定义
def 函数名(参数):
pass
函数名命名规则:
字母、数字和下划线组成,和变量命名规则一致
2、函数的调用:
函数名()
2.函数参数和返回值
思考
刚才讲到了函数的定义,那函数里面可以传入哪些对象呢?
函数参数的定义
1、必备参数:
def func(x):
pass
2、默认参数:
def func(x, y=None):
pass
3、不定长参数:
def func(*args, **kwargs):
pass
参数的调用:
1、通过位置传递参数(未命名参数)
2、通过关键字传递参数(命名参数)
3.在python中参数无类型,参数可以接受任意对象,只有函数中代码才会对参数类型有限制
函数参数调用演示
1、必备参数:
def func(x):
print(x)
func(1)
2、默认参数:
def func(x, y=None):
print(x)
print(y)
func(1)
func(1, 2)
3、不定长参数:
def func(*args, **kwargs):
print(args)
print(kwargs)
func(1, 2, 3, a=4, b=5, c=6)
func(*(1, 2, 3), **{'a': 4, 'b': 5, 'c': 6})
函数的参数
必备参数:在函数调用的时候,必备参数必须要传入
默认参数:在函数调用的时候,默认参数可以不传入值,不传入值时,会使用默认参数
不定长参数:在函数调用的时候,不定长参数可以不传入,也可以传入任意长度。
其中定义时,元组形式可以放到参数最前面,字典形式只能放到最后面
3.常见内置函数
思考
Python中有哪些内置函数呢?
Python中简单内置函数
1、内置对象查看:dir(__builtins__)
常见函数:
len() 求长度
min() 求最小值
max() 求最大值
sorted() 排序
reversed() 反向
sum() 求和
进制转换函数:
bin() 转换为二进制
oct() 转换为八进制
hex() 转换为十六进制
ord() 字符转ASCII码
chr() ASCII码转字符
Python中高级内置函数
1、enumerate() : 同时列出数据和数据下标,一般用在 for 循环当中
2、eval():
一、取出字符串中的内容
二、将字符串str当成有效的表达式来求指并返回计算结果
3、exec(): 执行字符串或complie方法编译过的字符串
4、filter() : 过滤器
5、zip() : 将对象逐一配对
6、map(): 对于参数iterable中的每个元素都应用fuction函数,并将结果作为列表返回
常见内置函数
常见内置函数提供了一些处理的数据的方法,可以帮助我们提高开发速度
我们介绍了一些python比较常见的内置函数,大家了解即可,知道能做什么,能够得到什么结果就行
八、函数作用域与匿名函数
本节知识点
01. 高级内置函数
02. 匿名函数
03. 函数作用域
04. 递归函数
05. 闭包
1.高级内置函数
Python中高级内置函数
1、enumerate() : 同时列出数据和数据下标,一般用在 for 循环当中
2、eval():
一、取出字符串中的内容
二、将字符串str当成有效的表达式来求指并返回计算结果
3、exec(): 执行字符串或complie()方法编译过的字符串
4、filter() :过滤器
5、zip() : 将对象逐一配对
6、map(): 对于参数iterable中的每个元素都应用fuction函数,并将结果作为列表返回
2.匿名函数
思考
上节课的filter函数,可以过滤出列表中大于10的数据,但是使用都需要提前定义一个函数,有没有更加简便的方式呢?
匿名函数 lambda
filter(lambda x: x>10, li)
语法规则:
lambda 参数 : 表达式
匿名函数应用场景
简单函数:简单的函数,可以不用使用def定义一个函数,使用匿名函数即可
函数调用:类似于filter、map等函数里面,可以使用匿名函数来处理
提高开发效率:匿名函数的合理利用能够让那个代码更加简洁
3.函数作用域
思考
在函数里面也有可以定义变量,那函数里面的变量名如果和函数外面的变量名重名,会相互影响吗?
示 例:
外部不能访问函数内部变量:
def fun1():
x = 1
return x
函数内部能够访问函数外部变量:
x = 123
def fun2():
print(x)
return x + 1
函数里面不能修改函数外部变量:
x = 123
def fun3():
x = x + 1
return x
函数里面和函数外部变量名相同:
x = 123
print(x, id(x))
def fun4():
x = 456
print(x, id(x))
x += 1
return x
global 和 nonlocal
global:
x = 123
def fun1():
global x
x += 1
return x
nonlocal:
def fun2():
x = 123
def fun3():
nonlocal x
x += 1
return x
return fun3()
函数作用域
函数内部:函数内部的变量,作用域只在函数内部,函数内部不可以直接更改函数外部的变量
global:函数内部如果需要改变全局变量,就需要使用global修饰变量
nonlocal:在函数嵌套函数的情况下,同样也有函数作用域的问题,但是python3中提供了方便,只需要使用nonlocal就可以在里层函数内部修改外部函数变量
4.递归函数
思考
函数里面可以自身调用自身吗?
递 归
递归演示(阶乘):
def factorial(n):
if n == 1:
return 1
return factorial(n-1)*n
递归中可以函数自身调用自身,但是使用时类似于条
件循环一样,要有递归的终止条件
递归应用
使用递归时,常常可以让代码更加简洁
递归会占用比较多的内存,当递归次数比较多时,性能就会降低,
因此不建议多使用递归
5.闭包
思考
函数里面可以再定义函数,那函数里面定义的函数可以在外面调用吗?
如果可以的话,要怎么做呢?
闭 包
内嵌函数:
def fun1():
print('fun1()在被调用')
def fun2():
print('fun2()在被调用')
fun2()
闭包:
def fx(x):
x += 1
def fy(y):
return x*y
return fy
闭包是函数里面嵌套函数,外层函数返回里层函数,这种情况称之为闭包
闭包是概念,不是某种函数类型,和递归的概念类似,就是种特殊的函数调用
闭包可以得到外层函数的局部变量,是函数内部和函数外部沟通的桥梁
九、类定义、属性、初始化、析构
本节知识点
01. 类定义
02. 方法
03. 初始化和析构
1.类定义
思考
之前我们在数据类型里面学习到了列表的方法,那是怎么做的可以让列表里面放下这么多方法呢?
类 是一个独立存放变量(属性/方法)的空间
运算符“.”
— 用于进行变量空间的运算
类的定义:
class 类名:
pass
Person类
var 变量
查找变量var -> 实例 p ->转到类中查找-> 实例中找不到->
1.类的定义
类的定义:
class 类名:
pass
创建实例:
实例名 = 类名()
“类”与“实例”之间的关系
是一类事物的抽象,不是真是存在的。
描绘了该类事物的共性,
例如:“人类”、“猫类”、“狗类”
某类事物的具体个体,是该类事物的具体表现,它是真实存在的。
例如:“炎志”是具体的某个“人”
''小明''是某个具体的’人’
“加菲猫”是具体的某个“猫”
''汤姆猫'' 是某个具体的’猫‘
一个“实例”的“特征”,就是“属性”
class Persion(object):
pass
p1 = Persion()
p2 = Persion()
p1.name = '小明'
p1.age = 20
p2.name = '大华'
p2.age = 23
类属性和实例属性
类属性:在类里面定义的属性,可以通过类和实例访问
class Persion(object):
attr = '人'
实例属性:通过实例定义的属性,只能通过实例访问
P1 = Persion()
P1.name = '名字'
类的私有属性
在python中有两私有属性,分别是在属性前加 一个下换线(_) 和 两个下划线(__)
_x: 意义在于唤起用户的注意,看成私有属性,类对象和子类可以访问
__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
私有属性:
在 Python 中, _ 和 __ 的使用 更多的是一种规范/约定,没有真正限制的目的
类
定义:类的定义使用关键字 class
封装:类可以把各种对象组织在一起,作为类的属性,通过 . (点)运算符来调用类中封装好的对象
属性:变量在类中称为属性,但是类中的属性不仅仅只包含变量,函数等其他的对象也可以作为类的属性
2.方法
思考
类里面除了放属性之后,还可以放些什么呢?
可以不可以在类里面定义函数呢?
“方法”就是封装在类里的一种特殊的函数
class Hero(object):
def move(self):
print('ok!')
“实例方法” 的调用过程与 self
通常,将默认会传入的那个参数命名为self,用来表示调用这个方法的实例对象本身。
方法总是定义在类中的,但是却叫“实例方法”,因为它表示该类所有实例所共有的行为
方法
类方法:类中的方法,就是函数
self: 代表的是实例本身
调用:方法的调用和属性调用一样,通过点操作符调用,传参和函数传参一样
3.初始化和析构
思 考
在刚才,实例化之后才添加 实例属性,那有没有办法在实例化的时候就添加实例属性呢?
“初始化”特殊方法
在Python中有很多以双下划线开头且以双下划线结尾的固定方法。
他们会在特定的时机被触发执行。
__init__ 就是其中之一,它会在实例化之后自动被调用。以完成实例的初始化。
init 的参数传递过程
实例化
产生一个类的实例
Python自动调用
实例.__init__(参数)
转换为
类.__init__(实例,参数)
“析构”问题引入
刚才讨论了在实例化的时候,可以做一些操作,那么当实例被销毁的时候,是否也可以做些什么呢?
通常在实例被销毁的时候,会执行怎样的任务 ?
__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数。
提示开发者,对象被销毁了,方便调试。
进行以写必要的清理工作。
基于变量计数的对象销毁机制
当没有一个变量指向某个对象的时候,Python会自动销毁这个对象,以便回收内存空间。
del 关键字,可以删除一个变量的指向。
十、继承、多继承、魔术方法
本节知识点
01.继承 02. 多继承 03. 魔术方法
1.继承
思 考
刚刚的作业我们定义一个矩形类,有长、宽的属性,和计算面积的方法,那么现在我要定义一个正方形的类,也有长 宽两个属性(正方形的长宽是不是一样的),和计算面积的方法,那么这个类我们应该怎么定义呢?
class Rectangle: # 矩形类
def __init__(self,length,width):
self.length = length
self.width = width
def area(self):
areas = self.length * self.width
return areas
class Square: # 正方形类
def __init__(self,length,width):
self.length = length
self.width = width
def area(self):
areas = self.length * self.width
return areas
继承 问题引入
问题一: 两个中有大量重复的代码,是否能够只写一次? 抽象出一个更抽象的类,放公共代码
问题二: 继承的意义是什么? 重用代码,方便代码的管理和修改
问题三: 继承是复制变量空间吗? 只是引用,不会复制
从矩形类中派生正方形类(派生和继承是一个意思)
class Rectangle: # 矩形类
def __init__(self,length,width):
self.length = length
self.width = width
def area(self):
areas = self.length * self.width
return areas
class Square(Rectangle): # 正方形类
pass
继承搜索
如果找不到,转到其父类中查找
如果再找不到,转到其父类的父类中查找
访问类的属性或方法,不是变量空间的复制 !
思 考
正方形类继承矩形类之后,要求正方类在实例化的时候就判断是否满足正方形邻边相等的要求呢?
重用父类的 init
class Square(Rectangle): # 正方形类
def __init__(self, length, width):
if length == width:
super().__init__(length, width)
Rectangle.__init__(self, length, width)
这个 self 是正方形类的实例,不是矩形类的实例
调用父类 重写方法
当子类重写父类方法之后,子类如果想再次调用父类的方法,可以使用这两种方法
方式一:
父类名.方法名(self)
方式二:
super().方法名()
注意:用类名调用的时候,( )里面要写self
顶级基类 object
Python 2.x中默认都是经典类,只有显式继承了object才是新式类
Python 3.x中默认都是新式类,写不写object都一样,都继承object
bases 特殊属性
__base__ :查看继承的父类
__bases__:查看继承的全部父类
思考:为什么返回的是一个元祖 ?
2.多继承
思考
刚才讲到了继承,一个类可以继承一个类,继承之后可以使用父类的方法和属性,那一个类可以继承多个类吗?
如果可以继承多个类的话,那如果两个父类中有一样的方法的情况下,子类继承哪一个呢?
多继承
通过C类实例的方法调用来看
当继承多个父类时,如果父类中有相同的方法,
那么子类会优先使用最先被继承的方法
在上面的例子中,如果不想继承父类的方法怎么办呢?
重写父类方法之后,如果又需要使用父类的方法呢?
多继承 调用父类重写方法
当子类重写父类方法之后,子类如果想再次调用父类的方法,可以使用这两种方法
使用 super调用父类重名方法,可以通过类的__mro__属性来查看多继承的情况下,子类调用父类方法时,在父类中的搜索顺序
多继承
在python3中,类被创建时会自动创建属性 __mro__ 解析顺序
object是所有类的父类
基于多继承的 Mix-in 设计模式
最好,多继承就一层,且是最后一层
注意:一般,“Mix-in类”是继承的终点 !
多继承
mro():类在生成时会自动生成方法解析顺序,可以通过 类名.mro()来查看
super():可以来调用父类的方法,使用super的好处在于即使父类改变了,那么也不需要更改类中的代码
Mixin:是一种开发模式,给大家在今后的开发中提供一种思路
3.魔术方法
思考
在讲字符串拼接的时候,字符串可以直接相加,那我们自定义的类可以实现吗?
魔术方法
__add__ :当类的实例之间使用+号时,会自动调用__add__这个魔法方法
运算符方法(解一下即可,在实际中应用并不多):
__add__(self,other) # x+y
__sub__(self,other) # x-y
__mul__(self,other) # x*y
__mod__(self,other) # x%y
__iadd__(self,other) # x+=y
__isub__(self,other) # x-=y
__radd__(self,other) # y+x
__rsub__(self,other) # y-x
__imul__(self,other) # x*=y
__imod__(self,other) # x%=y
字符串表示 问题引入
在交互模式下输出的交互信息与直接print的信息有些不同,背后的原理是 ?
我们该如何使用这种机制 ?
str 和 repr
__str__ 和 __repr__
调用str函数来处理实例对象,如果对象没有定义__str__方法,则调用__repr__方法
调用repr函数来处理实例对象,则调用__repr__处理,
str和repr原理
在python中,__repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。
使用内置函数str和repr方法在处理对象的时候,分别调用的是对象的__str__ 和__repr__方法
调用str函数来处理输出的对象,如果对象没有定义__str__方法,则调用__repr__方法
调用repr函数来处理输出的对象,则调用__repr__处理,
使用print操作 会首先尝试 调用__str__方法 ,如果__str__方法没有定义,则调用__repr__方法
在交互模式下,输入对象 显示对象 __repr__ 方法的返回值
类的实例可以向函数一样被调用吗?
__call__方法:
正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 __call__ 方法
类中的一些查询相关信息的方法 (了解既可)
1、__class__ 查看类名
格式: 实例.__class__
2、__dict__ 查看全部属性,返回属性和属性值键值对形式
格式:实例.__dict__
3、__doc__ 查看对象文档,即类中(用三个引号引起来的部分)
格式:类名.__dict__
4、__bases__ 查看父类
格式:类名.__base__
5.__mro__ 查看多继承的情况下,子类调用父类方法时,搜索顺序
格式:子类名.__mro__
实例.__class__.__mro__
魔术方法应用场景
__str__和__repr__:str和repr都是分别调用这两个魔术方法来实现的
原理:在类中,很多事情其实调用的魔术方法来实现的
作用:通过合理的利用魔术方法,可以让我们更加方便的展示我们的数据
十一、描述器 与 装饰器
本节知识点
01. __new__方法和单例模式
02. 定制属性访问
03. 描述符
04. 装饰器
1.new__方法和单例模式
问题思考:
__new__方法什么时候会被调用,它能做什么?
类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?
什么是单例模式?
new方法
四个点理解__new__方法
1、__new__方法是在 类 创建实例 的时候自动调用的。
2、实例是通过类里面的__new__方法是在 类 创建出来的。
3、先调用__new__方法创建实例,再调用 __init__方法初始化实例。
4、__new__方法,,后面括号里的cls代表的是类本身
创建实例的时候,自动调用了__new__,方法和__init__方法,并且是先调用的__new__再调用的__init__方法,打印 cls 的时候显示的这个 类
单列模式
定义一个私有属性__instance等于None
然后我们判断它是不是等于None,如果等于None,我们调用父类的方法创建一个实例对象,并把返回的对象赋值给 __instance,并且返回__instance
如果__instance不等于None,那就说明已经创建了对象我们直接把__instance返回出去。
单例模式实现的原理:
通过重写__new__方法,让__new__只能进行一次实例创建。
两个实例的ID是相同的,意味着第二次创建的时候,并没有真正的去创建,而是引用的第一次创的实例,同一个实例的不同名字
new方法
初始化函数之前:__new__方法会在初始化函数 __init__ 之前执行
单例模式:利用这个 __new__ 可以很方便的实现类的单例模式
合理利用:__new__ 方法合理利用可以带来方便,常应用在类的单例模式
2.定制属性访问
思 考
如何判断一个实例里面有某个属性呢?
怎样删除实例属性呢?
同样的怎样删除变量呢?
定制属性访问
1、查:
hasattr(re, 'length') # 返回bool值
getattr(re, 'length') # 返回属性值
b. __getattribute__('length') # 返回属性值
2、增:
b.aaa = 1
setattr(b, 'bbb', 2)
b.__setattr__('ccc', 3)
3、改:
setattr(b, 'length', 6)
b.__setattr__('length', 5)
3、删:
delattr(b, 'ccc')
b.__delattr__('bbb')
del b
getattr / hasattr / setattr / delattr
getattr(object, ’name’[, default]) -> object.name
hasattr(object, ’name’) ->
def hasattr(object, name_string):
try:
getattr(object, name_string)
return True
except AttributeError:
return False
setattr(object, ’name’, value) -> object.name = value
delattr(object, ’name’) -> del object.name
定制属性访问
re = Rectangle(3, 4) # 矩形类实例
def __getattr__(self, item):
print('no attribute')
当属性不存在时,如果定义了此方法,则调用方法
定制属性访问
b.length
b.__getattribute__('length')
属性值存在:返回属性值
属性值不存在:调用__getattr__未定义时报错
定制属性访问
hasattr:判断是否存在属性,如果属性存在则进行下一步操作
getattr:得到属性值
setattr:设置属性
3.描述符
思 考
如果在一个类中实例化另一个类,对这个属性进行访问的时候怎么做的?
描述符
描述符协议:python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有:
__get__(), __set__(), 和__delete__()。
如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符
魔术方法
描述符大家了解即可
魔术方法的作用其实是让开发人员能够更加灵活的控制类的表现形式
4.装饰器
思 考
之前我们讲了闭包,闭包中可以传入一个函数吗?
装饰器
能够实现在不修改原来的函数的基础上添加功能。
def fun(func):
def inner():
print("== 装饰器 ==")
func()
return inner
@fun # fun 的功能其实就是相当于 fu = fun(fu()) 这一句代码
def fu():
print("基础功能代码")
func()
内置装饰器
python的类里面中还有三个内置的装饰器:
@property:
作用是将类里面的一个方法变成属性
@classmethod:标识类方法的
@staticmethod :静态方法
类装饰器
class Test_Class:
def __init__(self, func):
self.func = func
def __call__(self):
print('类')
return self.func
@Test_Class�def fun_test():
print('这是个测试函数')
类也可以做装饰器,但是需要定义 __call__ 方法
装饰器参考
查看函数运行时间:
import time
def run_time(func):
def new_fun(*args,**kwargs):
t0 = time.time()
print('star time: %s'%(time.strftime('%x',time.localtime())) )
back = func(*args,**kwargs)�
print('end time: %s'%(time.strftime('%x',time.localtime())) )
print('run time: %s'%(time.time() - t0))
return back
return new_fun
装饰器
修饰函数:修饰函数
增加功能:给函数增加功能
内置装饰器:三个内置装饰器是需要掌握的,在项目中会经常使用
十二、文件
本节知识点
01. 内置装饰器
02. 文件基本操作
03. 上下文管理
04. IO流
05. 使用工具
1.内置装饰器
python的类里面中还有三个内置的装饰器:
@property:
作用是将类里面的一个方法变成属性
@classmethod:标识类方法的
@staticmethod :静态方法
2.文件基本操作
思考
我们的程序都是运行在内存中的,内存是不可持久化存储的,那怎样才能持久存储呢?
文件
1、打开文件:
path = 'test.txt'
path = r'/home/pyvip/py_case/test.txt'
file = open(path, 'w+')
2、写入:
file.write('Python')
file.flush()
file.writelines([1, 2, 3])
3、读取与关闭:
file.read()
file.readline()
file.readlines()
file.close()
4、查看与移动文件指针:
file.tell()
file.seek(0)
文件打开的模式:
模式 | 描述 |
---|---|
r | 以读方式打开文件,文件指针默认放在文件开头,文件不存在则报错 |
r+ | 打开一个文件用于读写,文件指针默认放在文件开头,文件不存在则报错 |
w | 打开一个文件只用于写入,如果该文件存在则覆盖,如果不存在,创建文件 |
w+ | 打开一个文件只用于读写,如果该文件存在则覆盖,如果不存在,创建文件 |
a | 打开一个文件用于读写,如果该文件存在则覆盖,文件指针放在文件结尾(新的内容将会被写到已有的内容之后);如果不存在,创建新文件并进行写入 |
a+ | 打开一个文件用于读写,如果该文件存在,文件指针放在文件结尾,文件打开时会是追加模式; 如果不存在,创建新文件并进行读写 |
其他模式:rb rb+ wb wb+ ab ab+
加个b的作用:以二进制的格式打开文件,进行上述操作 。
文件
持久存储:保存内存中数据都是易丢失的,只有保存在硬盘中才能持久的存储,保存在硬盘中的基本方法就是把数据写入文件中
打开与关闭:在python中文件的打开与关闭变得十分简单快捷,文件在关闭的时候就会自动保存
写入与读取:文件的写入和读取是必须要十分熟练的内容
3.上下文管理
思考
文件能够自动关闭吗?
whith
with open(path, 'r') as f:
print(f.read())
with能够自动关闭文件,不需要执行close方法
上下文管理
with:使用with打开文件,则文件不需要自己关闭,会自动的关闭
__enter__:进入时需要执行的代码,相当于准备工作
__exit__:退出时需要执行的代码,相当于收尾工作
4.IO流
思考
文件可以持久存储,但是现在类似于临时的一些文件,不需要持久存储,如一些临时的二维码等,这个不需要持久存储,但是却需要短时间内大量读取,这是时候还是只能保存在文件里面吗?
StringIO
1、创建IO操作:
import io
sio = io.StringIO()
2、写入:
sio.write(str(i))
3、读取:
sio .getvalue()
StringIO在内存中如同打开文件一样操作字符串,因此也有文件的很多方法
当创建的StringIO调用 close() 方法时,在内存中的数据会被丢失
BytesIO
创建BytesIO:
import io
bio = io.BytesIO()
写入:
bio.write(b'abcd')
读取:
sio .getvalue()
BytesIO 和 StringIO 类似,但是BytesIO操作的是 Bytes数据
5.使用工具
思考
文件可以直接新建,但是现在如果需要创建文件夹和移动文件夹怎么办呢?
os 操作系统交互
os 模块提供python和操作系统交互的接口
直接调用系统命令
os.system('ls')
通用路径操作:
os.path
os.path.join(r'/home/pyvip', r'pycase')
文件目录操作:
os.mkdir('test')
os.rename('test', 'test1')
...
os 提供了Python和操作系统交互方式,只要是和操作系统相关,就可以尝试在os模块中找方法
shutil 高级文件操作
shutil 模块提供了许多关于文件和文件集合的高级操作
移动文件
shutil.move()
复制文件夹
shutil.copytree()
删除文件夹
shutil.rmtree()
十三、异常
本节知识点
01. 异常
02. 异常处理
03. 断言
1.异常
思考
什么是异常? python中有哪些异常?
如何通过程序的报错来找到有问题的代码?
Python的异常结构(基于继承)
在 Python 中所有的异常都是继承自 BaseException
直接分为四大类:
SystemExit:Python退出异常
KeyboardInterrupt: 键盘打断(Ctrl+C)
GeneratorExit: 生成器退出(下次课再讲)
Exception: 普通异常(只会使用这部分的异常)
做一个会提问的人
在今后的学习和工作过程中,会遇到大量的报错,每个开发人员都必须掌握查找和解决报错的能力
在自己无法解决需要寻求帮助时,也要掌握如何描述问题,把问题描述清楚的能力,掌握如何提问的技巧,这会大大节省双方的时间和精力
2.异常处理
本节思考
问题一:异常通常会带来怎样的问题 ?程序停止了
问题二: 我们如何能防止这个问题, 从而利用异常 ?
问题三: 具体的该怎么做 ?
异常处理 try … except …
try:
print("== 可能出现错误的代码区 ==")
except:
print("== 出现错误的代码区 ==")
注意:
try 后面必须跟上 excep
捕获具体的异常
except 后面可以写上捕获具体的异常类型
还可以通过as 把捕获的异常信息 储存到后面的变量里面
关于 Exception 及其 子类 的解释
代码中会出现的异常都是 Exception 的子类, 因此在 except 中只需要在最后加上 Exception 即可
在捕获异常的过程中,会从上倒下依次对比异常,找到之后就不会再往后查找
更加丰富的结构
注意事项:
1. try 下面放可能出错的代码
2. except try下面的代码出错后,会执行except下面的代码
3. else try下面代码没有错误,执行else下面的代码
4. finally 不管try下面的代码有没有出错,始终都会执行
扩展(自定义异常类型)
raise 主动抛出异常
格式:raise 异常类型
注意:raise 是主动抛出后面写的异常类型
异常
try:将可能会发生异常的代码放在try中,就可以得到异常,并做相应处理
except: 用来接受异常,并且可以抛出或者返回异常
else和finally:
else:在没有异常的时候会执行
finally:不管是否有异常,都会执行
3.断言
本节思考
问题一: 如何能在代码中强制要求一个条件满足 ?
问题二: 是否有专门的语法来完成 ?
断言 assert
1、 assert 1 == 1
` assert 1 == 2
2、 断言语句是将调试断言插入程序的一种便捷方式
assert 的语法规则是:
表达式返回 True 不报错
表达式返回 False 报错 报 AssertionError
十四、迭代器 与 生成器, 模块与包
本节知识点
01. 推导表达式
02.生成器
03.迭代器
04. 模块
05. 包和包管理
1.推导表达式
思考
得到一个元素为1到10的列表,可以怎么做?
列表推导
循环添加:
li = []�for i in range(1,11):
li.append(i)
列表推导:
li = [i for i in range(1, 11)]
列表推导+条件判断:
l2 = [i for i in range(1, 11) if i % 2 == 0]
列表推导+三目运算:
l3 = [i if i % 2 == 0 else 0 for i in range(1, 11)]
集合和字典推导
集合推导:
{i for i in range(1,10)}
字典推导:
{i: j for i, j in enumerate(li)}
推导表达式
推导表达式相对于for循环来处理数据,要更加的方便
列表推导表达式使用更加的广泛
2.生成器
思考
把推导式放在小括号()里面返回的,是一个generator对象,这个是什么?
创建生成器的两个方法
方法 一:列表推导式的 [ ] 改成 ( )
b = ( x for x in rang(10) )
next(b)
方法 二:在函数里面加上yield
def fun(num):
a = 0
while a<num:
yield a
a += 1
ge = fun(10)
next(ge)
注意:
生成器不会一下子把所以内容生成出来,在我们需要的时候用next()去生成
yield运行规则
yield 一个对象
规则:
1.返回这个对象 2.暂停这个函数 3.等待下次next()重新激活运行
注意:
yield 表达式只能在函数中使用,在函数体中使用 yield 表达式可以使函数成为一个生成器
yield 可以返回表达式结果,并且暂定函数执行,直到next激活下一个yield
Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果,从而节省大量的空间,这也是生成器的主要好处
3.迭代器
可迭代对象与迭代器
思考一: 迭代是一个怎样的过程 ?
就是一个依次从数据结构中拿出东西的过程 => Iterator
思考二: 能否用更加低级的while来实现 ?
可以的,但是,需要自己控制下标并获取对应的元素
思考三: 可迭代对象与迭代器的区别 ?
区分 可迭代对象 和 迭代器
from collections import Iterable ,Iterator
可迭代对象: Iterable
可迭代对象能用for循环进行遍历
可以使用 isinstance() 判断一个对象是否是 Iterable 对象:
迭代器: Iterator
迭代器不仅可以通过for进一行遍历,可以通过next取值
可以使用 isinstance() 判断个对象是否是 Iterator :
迭代
for 迭代变量 in 可迭代对象
每一次循环都会自动让"迭代变量"指向"下一个元素"
the_list = [1,2,3,4,5]
for index in the_list:
print(index)
for 实现原理
the_list = [1,2,3,4,5]
itr = iter(the_list)
try:
while True:
var = next(itr)
print(var)
except StopIteration:
pass
从可迭代对象生成一个迭代器
iter(可迭代对象)
next(迭代器)
迭代器
迭代器对象本身需要支持以下两种方法,它们一起构成迭代器协议:
iterator.__iter__()
iterator.__next__()
取值:
next(iterator)
iterator.__next__()
注意:如果迭代器值取完之后,会返回 StopIteration 错误
扩展提示:通过定义__iter__和__next__方法,以自定义迭代器
4.模块
本节思考
思考一:什么是模块 ?
模块就是一个python文件
思考二:为什么需要导入别的模块 ?
在开发中,我们可以分配不同的程序员,不同部分的工作,最后通过导入,将所有人的成果结合在一起
思考三:导入的过程大致是怎样的 ?
import --> 执行导入的文件 --> 在当前这个文件里生成一个模块对象
模块
模块:在python中,模块就是一个py文件,可以使用下面两种方法导入
import datetime
from datetime import datetime (as this_datetime)
注意:datetiame是一个常用的时间处理模块
1.在同一目录下,可直接使用上面两种方法去导入
2.在不同目录下,需要使用 sys.path 添加路径
sys.path.append('path')
在python3中导入后,会在当前路径下生成一个 __pycache__ 文件夹
导入语法 与 导入路径
import 模块名
直接导入,使用时模块名.函数名()
import 模块名 as 新名字
导入以后,重新命名使用 新名字.函数名()
from 模块名 import 函数名
部分导入,导入模块内部的东西,而不要模块可以在模块里用一个变量 __all__控制被导入函数
sys.path
用于存放导入路径的列表,类似于环境变量中的 PATH
if name == 'main':
__name__:
python会自动的给模块加上这个属性,如果模块是被直接调用的,则 __name__ 的值是 __main__,否则就是该模块的模块名
if __name__ == '__main__':
该语句可以控制代码在被其他模块导入时不被执行
5.包和包管理
本节思考
思考一:什么是包 ?包,就是包含了很多模块的文件夹
思考二:如何构造一个包 ?首先需要把py文件放入包中,并且加一个__init__.py文件
思考三:加入包的概念后,导入规则是否有变化 ?
通过包,我们加入了层级导入
包和包管理
包概念:
把很多模块放到一个文件夹里面,就可以形成一个包
包管理:
当把很多模块放在文件中时,为了方便引用包中的模块,引入了包管理
__init__.py:
在包管理中,加入此模块,则包名可以直接通过属性访问的方式,访问此模块内的对象,文件内容可以为空
相对路径导入:
在包管理中,可以通过 . (一个点) 和 .. (两个点)分别来导入同层和上一层的模块
相对路径导入
引入作用:
在包中,如果包中模块要导入同一包中的其他模块,就必须使用此方法导入
使用方法:
from .module(..module) import obj (as new_name)
引入之后的影响:
当一个模块中出现此导入方式,则该模块不能被直接运行,只能被导入
十五、正则表达式
本节知识点
一、正则表达式的概念
二、re模块
三、元字符
一、正则表达式的概念
正则表达式概念问题引入
问题一: 什么是正则表达式 ?
问题二: 正则表达式主要解决什么问题 ?
正则表达式所面向的问题
1、判断一个字符串是否匹配给定的格式(判断用户注册帐号是否满足格式)
2.从一个字符串中按指定格式提取信息(抓取页面中的链接)
3.判断用户提交的邮箱的格式是否正确
二、re模块
在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个模块来操作,名字为re
import re
1、findall()方法:在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表
import re
s = 'python123'
ss = re.findall('python',s)
print(ss)
2、match()方法
re.match() 尝试从字符串的起始位置匹配一个模式,匹配成功 返回的是一个匹配对象(这个对象包含了我们匹配的信息),如果不是起始位置匹配成功的话,match()返回的是空,
import re
s = 'python123'
ss = re.match('python',s)
print( ss.group() )
注意:
match()只能匹配到一个
1.可以通过group()提取匹配到的内容
2.可以通过span()提取匹配到的字符下标
2、search()方法
re.search() 扫描整个字符串,匹配成功 返回的是一个匹配对象(这个对象包含了我们匹配的信息)
import re
s = 'python123'
ss = re.search('python',s)
print(ss)
注意:
search()也只能匹配到一个,找到符合规则的就返回,不会一直往后找
re.match与re.search的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,
re.search:匹配整个字符串,如果一直找不到则报错
三、元字符
问题引入
问题一: 什么是元字符 ?(本身具有特殊含义的字符)
问题二: 常用元字符有哪些 ?
问题三: 怎样才能匹配这些字符本身 ?
单字符匹配
字符 | 功能 |
---|---|
. | 匹配任意1个字符(除了\n) |
[] | 匹配[]中列举的字符 |
\d | 匹配数字,即 0 - 9 |
\D | 匹配非数字,即不是数字 |
\s | 匹配空白,即空格,tab键 |
\S | 匹配非空白 |
\w | 匹配单字符,即 a-z, A-Z, 0-9, _ |
\W | 匹配非单词字符 |
代表数量的元字符
字符 | 功能 |
---|---|
* | 匹配前一个字符出现0次或 无限次,即可有可无 |
+ | 匹配前一个字符出现1次 或无限次,即至少有1次 |
? | 匹配前一个字符出现1次 或0次,即要么有1次,要么没有 |
{m} | 匹配前一个字符出现m次 |
{m,} | 匹配一个字符至少出现m次 |
{m,n} | 匹配前一个字符出现从m到n 次 |
表示边界的元字符
字符 | 功能 |
---|---|
^ | 匹配字符串开头 |
& | 匹配字符串结尾 |
\b | 匹配一个单词的边界 |
\B | 匹配非单词边界 |
分组匹配
字符 | 功能 |
---|---|
| | 匹配左右任意一个表达式 |
(ab) | 将括号中字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?P<name>) | 分组别名 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
贪婪与非贪婪
正则默认都是用贪婪模式去匹配数据的,就是尽可能多的匹配符合要求的数据,在非贪婪模式下,始终找最短匹配
s = '<html> 123<h2>abc</h2> </html>'
re.findall(r'<.*>',a) # 贪婪
#结果: [ '<html> 123<h2>abc</h2> </html>' ]
s = '<html> 123<h2>abc</h2> </html>'
re.findall(r'<.*?>',a) # 加上 ? 非贪婪
#结果: [ '<html>',<h2>'','</h2>','</html>' ]