Python
概况
- 1989年底,荷兰程序员 Guido van Rossum 开发了Python语言,并于1991年初发行第一个公开发行版。
-
版本:Python3.x,于2009年发布。
-
特点:
-
跨平台:支持Windows、Linux、MAC os等主流操作平台
-
可移植:代码通常不需要多少改动就能移植到其他平台上使用
-
可扩展:Python语言由C语言编写,可以使用C语言重写Python的模块
-
交互式:人机互动和调试代码片段
-
大量标准库和第三方库
-
社区活跃,贡献者多
-
开源语言,发展动力巨大
-
面向对象OOP(Object-Oriented Programming)
-
-
安装
Windows安装
-
Python官网:https://www.python.org/downloads/windows/
-
embeddable zip file 是压缩包版本,即便携版,解压可用
executable installer (建议)是可执行的安装版本,即离线版,下载到本地后可以直接安装
web-based installer 是联网安装版,体积很小,但需要保持网络畅通
-
建议使用离线安装版(executable installer),这样软件会帮你设置系统变量,否则需要自己添加。
-
# Windows安装Python
注意:如果在Windows 7环境下安装Python 3,需要先安装ServicePack 1补丁包,可以在Windows的命令行键入`winver`命令,来查看系统是否安装了该补丁包。如果没有该补丁包,一定要先通过"控制面板——》操作中心——》Windows Update——》更改设置——》更新系统"或者类似"CCleaner"这样的工具自动安装该补丁包,安装完成后重启Windows系统,然后再开始安装Python环境。
在官网下载安装程序,双击运行:
——》Install Python x.x:选择自定义安装"Customize installation",勾选为所有用户使用"Install launcher for all users (recommended)",勾选添加环境变量"Add Python x.x to PATH"
——》Optional Features:全部勾选。其中"pip"是python的库。
——》Advanced Options:勾选"Install for all users","Add Python to environment variables","Precompile Standard Library",选择安装路径"Customize install location"
如果没有勾选添加环境变量等选项,则手动设置环境变量:
——》"控制面板——》系统和安全——》系统——》高级系统设置——》系统属性的高级——》环境变量",找到环境变量"PATH","新建"增加Python的安装路径
验证:
——》在Windows的命令行键入`python -V`或`pyhon --version`查看版本,或键入`python`命令进入python使用界面
——》在Windows的命令行键入`pip`命令
Linux安装
- Python官网:https://www.python.org/downloads/
- 大多数Linux版本已经预装Python 3
// Linux安装Python
// 安装依赖
]# dnf install -y gcc gcc-c++ zlib-devel openssl-devel readline-devel libffi-devel sqlite-devel tcl-devel tk-devel
// 源码安装
]# tar -zxf Python-3.x.tar.gz
]# cd Python-3.x
]# ./configure --prefix=/usr/local
]# make && make install
// 大多数Linux版本已经预装Python 3
]# python3 -V
Python 3.6.8
基础使用
- 注释及续行:
- 注释:
#
。注释可以在一行的任何地方开始。 - 续行:
\
- 注释:
- 同一行多个语句:
- 使用
;
分割同一行的多个语句。
- 使用
基础语句
输出语句:print
-
print(xxx)
:将内容输出到终端。字符串使用引号。 -
+
:字符串连接符或数值加号。符号左右的数据类型要一致。字符串类型为连接符,数值类型为加号。 -
,
:添加分隔符。默认分隔符为空格。 -
sep="xxx"
:设置分隔符。 -
end="xxx"
:设置结束符。默认结束符为\n
。
[root@localhost day01]# cat demo01_print.py
print("hello world") # `+`:字符串连接符
print("hello"+" "+"world")
print("hello" + " " + "world")
print(22+45) # `+`:数值加号
print("22+45=",22+45) # `,`:添加分隔符。默认分隔符为空格
print("22+45=",22+45,sep="++") # sep:设置分隔符
print("22+45=",22+45,sep="--")
print("22+45=",22+45,sep="**",end="??") # end:设置结束符。默认结束符为\n
print("22+45=",22+45,sep="**",end="\n")
[root@localhost day01]# python3 demo01_print.py
hello world
hello world
hello world
67
22+45= 67
22+45=++67
22+45=--67
22+45=**67??22+45=**67
[root@localhost day01]#
数据类型转换
type(xxx)
:查看数据的数据类型。str(xxx)
:其他数据类型转字符串str。int(xxx)
:其他数据类型转整数int。
[root@localhost day01]# cat demo02_int_str.py
num = 50 # int
print(num,type(num))
# str(xxx):其他数据类型转字符串str
num = str(num) # str
print(num,type(num))
# int(xxx):其他数据类型转整数int
num = int(num) # int
print(num,type(num))
[root@localhost day01]# python3 demo02_int_str.py
50 <class 'int'>
50 <class 'str'>
50 <class 'int'>
输入语句:input
input("提示信息")
:接收从键盘键入的数据,返回值为字符类型。
[root@localhost day01]# python3
# 从键盘获取值,返回值一定是字符类型
>>> input()
zhangsan # 键入zhangsan
'zhangsan'
# 根据提示信息,从键盘获取值
>>> input('username: ')
username: zhangsan # 键入zhangsan
'zhangsan'
# 根据提示信息,从键盘获取用户名,并赋值给变量user
# 变量的赋值,两边空格可有可无
>>> user = input('id: ')
id: 100 # 键入100
>>> print(user) # 打印变量user的值
100
>>> type(user)
<class 'str'>
# 通过input() 从键盘获取的值,一定是字符串类型的
>>> num = input('number: ')
number: 10
>>> print(num)
10
>>> num + 5 # input()获取的值都是字符类型的,字符串和数字不能参加运算
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not int
>>> type(num) # 变量num是字符串类型str
<class 'str'>
# int()函数将字符串转换为数值类型,并进行运算
>>> int(num) + 5 # 整数类型int的两个值可以运算
15
# str()函数将数字类型转换为字符串,并进行拼接操作
>>> print(num)
10
>>> num + str(5) # 字符串类型str的两个值可以拼接
'105'
帮助
[root@localhost day01]# python3
>>> help(input)
变量
- 在 Python 中,每个变量 在使用前都必须被赋值,变量 被赋值之后才会被创建。
- 例如:
n += 1
不能运行,因为n没有被赋值,也没有初始值,无法运行。
- 例如:
变量名 = 变量值
:赋值变量。- 变量值可以是函数或语句的执行结果。
- 变量名第一次使用是定义变量,再次使用是使用之前定义过的变量。
- 变量名可以由大小写字母、数字、下划线组成,区分大小写,不能以数字开头,不能为关键字。
- Python中,变量的数据类型不是固定的,变量的数据类型取决于变量值。
- Python中没有自增1
++
、自减1--
。
# 练习:买包子,单价1.5、数量10,求总价
[root@localhost day01]# cat demo03_buy01.py
price = 1.5
number = 10
money = price * number
print("money:",money)
[root@localhost day01]# python3 demo03_buy01.py
money: 15.0
# 练习:买包子,单价1.5、数量10,总价打9折,求总价
[root@localhost day01]# cat demo03_buy01.py
price = 1.5
number = 10
money = price * number
money *= 0.9
print("money:",money)
[root@localhost day01]# python3 demo03_buy01.py
money: 13.5
运算符
算术运算符
- 算术运算符:
+
,-
,*
,/
//
:取商。9 // 2 = 4
%
:取余。9 % 2 = 1
**
:幂。2 ** 3 = 8
+=
、-=
、*=
、/=
、//=
、%=
、**=
- 注意:不支持
++
和--
[root@localhost day01]# python3
>>> 5/3 # 除法
1.6666666666666667
>>> 5//3 # 取商
1
>>> 5 % 3 # 取余
2
比较运算符
- 比较数值:结果返回True或False
==
:相等。也可以比较字符串。
!=
:不等。也可以比较字符串。>
:大于。
<
:小于。
>=
:大于等于。
<=
:小于等于。
[root@localhost day01]# python3
>>> "a" == "a"
True
>>> "a" != "a"
False
>>> "a" != "b"
True
>>> "1" == 1 # 字符串与数值不等
False
>>> 5 > 3
True
>>> 10 < 15 < 20 # 比较10是否小于15,并且15是否小于20,为真,不方便阅读,少用; 可写为:10 < 15 and 15 < 20
True
>>> 10 < 15 > 13 # 比较10是否小于15,并且15是否大于13,为真,可写为:10 < 15 and 15 > 13
True
逻辑运算符
- 逻辑运算符:结果返回True或False
and
:与。x and y
or
:或。x or y
not
:非。not x
[root@localhost day01]# python3
>>> 5 > 3 and 10 > 5
True
>>> 5 > 3 or 10 > 50
True
>>> not 5 > 3
False
>>> 10 > 50
False
>>> not 10 > 50
True
数据类型
布尔类型 bool
- 布尔类型
bool
:取值(区分大小写) True 或 False。- 作算术运算时,True为1,False为0。
[root@localhost day01]# python3
>>> type(True)
<class 'bool'>
>>> 1<2
True
>>> type(1<2)
<class 'bool'>
数值类型 int、float
- 数值类型:
int
:整数(有符号)。float
:浮点数(小数)。
[root@localhost day01]# python3
>>> type(5)
<class 'int'>
>>> type(5.0)
<class 'float'>
>>> type(-1)
<class 'int'>
>>> type(-12.5)
<class 'float'>
>>> type(0)
<class 'int'>
>>> type(0.00)
<class 'float'>
# 作算术运算时,True为1,False为0
>>> True + 3
4
>>> False * 3
0
- 整数显示方式:Python 默认以十进制数 显示
0b数字
或0B数字
将二进制数(Binary,0~1)转换为十进制数。0o数字
或0O数字
将八进制数(Octal,0~7)转换为十进制数。0x数字
或0X数字
将十六进制数(Hexadecimal,0~F)转换为十进制数。bin(xxx)
:将十进制数xxx,转换为二进制数。oct(xxx)
:将十进制数xxx,转换为八进制数。hex(xxx)
:将十进制数xxx,转换为十六进制数。
[root@localhost day01]# python3
# python 默认以十进制数显示,十进制数范围:0 ~ 9
>>> 23
23
# 以0b或0B开头表示二进制,0b10:将二进制数10,以十进制方法进行显示
# 十进制数10转为二进制方法: 1*2的1次方 + 0*2零次方 = 1*2 + 0*1 = 2
# 二进制数范围:0,1
>>> 0b10 # 注意,0是数字不是英文
2
# 以0o或0O开头表示8进制,0o23:将8进制数23,以十进制方法进行显示
# 8进制数23转为十进制方法: 2*8的1次方 + 3*8零次方 = 2*8 + 3*1 = 19
# 8进制数范围:0 ~ 7
>>> 0o23
19
# 以0x或0X开头表示16进制,0x23:将十六进制数23,以十进制方法进行显示
# 十六进制数23转为十进制方法: 2*16的1次方 + 2*16零次方 = 2*16 + 3*1 = 35
# 16进制数范围:0 ~ 9,a ~ f(不区分大小写)
>>> 0x23
35
>>> 0xAF
175
>>> 0xaf
175
>>> bin(100) # 函数bin():将十进制数100,转换为二进制数
'0b1100100'
>>> oct(100) # 函数oct():将十进制数100,转换为八进制数
'0o144'
>>> hex(100) # 函数hex():将十进制数100,转换为十六进制数
'0x64'
>>> hex(0o144)
'0x64'
字符串类型 str
- 字符串类型
str
:成对引号之间的字符集合。- 可以是成对的单引号或双引号,效果一样。
引号
- 成对的引号中间可以使用其他引号。
- Python 支持三引号(三个连续的单引号或者双引号),可以用来保存用户输入的格式(原样输出),三引号也是成对的。
[root@localhost day01]# python3
# 在成对的引号中使用其他引号
>>> sentence = "hello nfx, I'm your baby~"
>>> print(sentence)
hello nfx, I'm your baby~
>>> sentence = 'hello nfx, I"m your baby~'
>>> print(sentence)
hello nfx, I"m your baby~
# 在成对的三引号中使用单引号和双引号
>>> sentence = """hello "nfx", I'm your baby~"""
>>> print(sentence)
hello "nfx", I'm your baby~
>>> sentence = '''hello "nfx", I'm your baby~'''
>>> print(sentence)
hello "nfx", I'm your baby~
# 三引号可以保存用户输入的格式(原样输出)。可以是三个单引号,也可以是三个双引号
>>> users=""" tom
... bob
... alive
... """
>>> print(users)
tom
bob
alive
>>> users=''' tom
... bob
... alive
... '''
>>> print(users)
tom
bob
alive
索引
- 字符串的索引:字符串中字符的位置。
len("字符串")
:返回字符串长度(字符个数)。变量名[索引]
:返回该变量的该索引(正向或反向都可)的字符。- 正向递增索引(从左往右):左起第一个字符的索引从0起计
- 反向递减索引(从右往左):右起第一个字符的索引从-1起计
- 每个字符的索引:正向递增索引 - 反向递增索引 = 字符串长度
- 索引越界报错:
IndexError
- 字符串类型可以重新赋值,但不能修改值的字符。
[root@localhost day01]# python3
>>> py_str = 'python'
>>> len(py_str) # 使用函数len(),统计变量py_str的字符长度
6
>>> py_str[0] # 取出变量py_str中正数第一个字符。0-6=-6,倒数第六个字符
'p'
>>> py_str[5] # 取出变量py_str中正数第六个字符。5-6=-1,倒数第一个字符
'n'
>>> py_str[-1] # 取出变量py_str中倒数第一个字符。-1+6=5,正数第五个字符
'n'
>>> py_str[-6] # 取出变量py_str中倒数第六个字符。-6+6=0,正数第一个字符
'p'
>>> py_str[6] # 索引越界报错IndexError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> py_str[0] = 'l'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
切片 [::]
字符串[起始索引:终止索引:步长]
:得到子字符串(默认含头去尾),不改变原字符串。- 子字符串含头去尾:包含起始索引的字符,不包含终止索引的字符。
- 步长n:每n个字符取第一个字符。步长为负数:反向取值。
字符串[起始索引:终止索引]
:省略步长默认为1。字符串[:终止索引]
、变量名[:终止索引:步长]
:省略起始索引则从头。也可以使起始索引超范围。字符串[起始索引:]
、变量名[起始索引::步长]
:省略终止索引则到尾(含尾)。也可以使终止索引超范围。- 特殊地:
字符串[:5]
:前5个字符[0,5)
。字符串[-5:]
:后5个字符[-5,-1]
。
- 特殊地:
[root@localhost day01]# python3
>>> py_str = 'python'
>>> len(py_str)
6
# 正向索引和反向索引混用,省略步长默认为1。含头去尾
>>> py_str[1:4] # [索引1,索引4),不含索引4
'yth'
>>> py_str[-5:-2] # [索引-5,索引-2),不含索引-2
'yth'
>>> py_str[1:-2] # [索引1,索引-2),不含索引-2
'yth'
>>> py_str[-5:4] # [索引-5,索引4),不含索引4
'yth'
# 直接使用字符串
>>> "python"[1:4]
'yth'
# 到尾
>>> py_str[1:5] # [索引1,索引5),不含索引5(尾)
'ytho'
>>> py_str[1:6] # 6超过索引范围不报错。[索引1,尾]
'ython'
>>> py_str[1:6000] # 6000超过索引范围不报错。[索引1,尾]
'ython'
>>> py_str[1:] # [索引1,尾]
'ython'
# 从头的
>>> py_str[0:5] # [头,索引5)
'pytho'
>>> py_str[:5] # [头,索引5)
'pytho'
>>> py_str[-7:5] # -7超过索引范围不报错。[头,索引5)
'pytho'
>>> py_str[-700:5] # -700超过索引范围不报错。[头,索引5)
'pytho'
# 所有字符
>>> py_str[:]
'python'
# 步长为正数:正向取值
# 步长为2:每2个字符取第一个字符
>>> py_str[::2] # 索引0,索引2,索引4
'pto'
>>> py_str[1::2] # 索引1,索引3,索引5(尾)。省略终止索引则到尾
'yhn'
# 步长为3:每3个字符取第一个字符
>>> py_str[1::3] # 索引1,索引4
'yo'
# 步长为负数:反向取值
>>> py_str[::-1] # 省略起始索引则从头,省略终止索引则到尾
'nohtyp'
>>> py_str[::-2] # 'nohtyp'第1(索引-1)、3(索引-3)、5(索引-5)的字符。省略起始索引则从头,省略终止索引则到尾
'nhy'
>>> py_str[-3:-5:-1] # 'nohtyp'第3(索引-3)、4(索引-4)的字符
'ht'
>>> py_str[-3::-2] # 'nohtyp'第3(索引-3)的字符开始到尾,步长为2,即第3(索引-3)、5(索引-5)的字符
'hy'
>>> py_str[:-5:-2] # 'nohtyp'从头到第4(索引-4)的字符结束,步长为2,即第1(索引-1)、3(索引-3)的字符
'nh'
包含于 in
、拼接 +
、重复 *
"短字符串A" in "长字符串B"
:判断字符串A是否包含于字符串B。- 注意:空字符串
'' in '字符串'
为True。
- 注意:空字符串
"短字符串A" not in "长字符串B"
:判断字符串A是否不包含于字符串B。"字符串A" + "字符串B"
:拼接字符串得到新字符串。"字符串" * 正整数
:重复字符串得到新字符串。
[root@localhost day01]# python3
>>> py_str = "python"
# 包含于`in`、不包含于`not in`。结果为bool
>>> 'tho' in py_str
True
>>> 'thn' in py_str
False
>>> 'thn' not in py_str
True
>>> '' in py_str # 特殊的,空字符串
True
>>> '' not in py_str
False
# 拼接`+`。数值为假发,字符串为拼接
>>> py_str + ' is good'
'python is good'
>>> py_str + 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not int
>>> py_str + ' 10'
'python 10'
# 重复`*`。数值为乘法运算,字符串为重复
>>> py_str * 3
'pythonpythonpython'
>>> "abc" * 3
'abcabcabc'
>>> 3 * "abc"
'abcabcabc'
列表类型 list
- 标量:只能存储一个值。例如:布尔类型、数值类型、字符串类型
列表:可以存储多个元素。
-
列表类型
list
(其他语言中通常叫做数组):用于存储一串信息,可以存储任意数量的元素。列表名=[元素1,元素2,元素n]
:定义列表的元素。元素可以是任意数据类型。
-
列表的索引类似于字符串的索引,表示元素的位置。正向递增(从0起计)、反向递减(从-1起计)。
len(列表)
:返回该列表的元素个数。列表[索引]
:返回该列表的该索引的元素。列表[索引] = 新元素
:给该索引的元素重新赋值,新元素可以是任意数据类型。列表.append[新元素]
:给该列表追加新元素,新元素可以是任意数据类型。列表名[起始索引:终止索引:步长]
:切片得到新列表。规则类似于字符串的切片。列表A + 列表B
:拼接列表得到新列表。必须均为列表类型list。元素 in 列表
:判断元素是否在列表中。
元素 not in 列表
:判断元素是否不在列表中。
[root@localhost day01]# python3
# 列表的存储任意数量的元素,元素可以是任意数据类型
>>> alist = [10, 20, 'tom','alice', [1,2]]
# len(列表名):查看列表的元素个数
>>> len(alist)
5
# 列表名[索引]:查看列表的元素
>>> alist[0]
10
>>> alist[-1]
[1, 2]
>>> type(alist[0])
<class 'int'>
>>> type(alist[-1])
<class 'list'>
# 切片
>>> alist[2:4] # 取出列表alist中,第二个到第四个元素,不包含下标为4的元素
['tom', 'alice']
>>> alist[2::2] # 到尾
['tom', [1, 2]]
>>> alist[:4:2] # 从头
[10, 'tom']
>>> alist[::-1] # 从右往左,反向取值
[[1, 2], 'alice', 'tom', 20, 10]
>>> alist[::-2] # [[1, 2], 'alice', 'tom', 20, 10],全部,步长为2
[[1, 2], 'tom', 10]
>>> alist[-1:-4:-2] # [[1, 2], 'alice', 'tom', 20, 10],第1个(索引-1)元素到第3个元素(索引-3),步长为2
[[1, 2], 'tom']
# 列表元素的重新赋值,新元素可以是任意类型
>>> type(alist[-1])
<class 'list'>
>>> alist[-1] = 100
>>> type(alist[-1])
<class 'int'>
>>> alist
[10, 20, 'tom', 'alice', 100]
# 列表追加元素,新元素可以是任意类型
>>> alist.append(200)
>>> alist
[10, 20, 'tom', 'alice', 100, 200]
>>> blist = ["test", 12, [3, 5]]
>>> alist.append(blist)
>>> alist
[10, 20, 'tom', 'alice', 100, 200, ['test', 12, [3, 5]]]
# 判断是否列表的元素
>>> 'tom' in alist # 字符串'tom'是否是列表alist的元素
True
>>> 'to' in alist
False
>>> 'to' not in alist
True
# 列表的拼接必须均为list类型,拼接后得到一个新列表
>>> clist = [10, 20, 'tom', 'alice', [1, 2]]
>>> type(clist)
<class 'list'>
>>> type(100)
<class 'int'>
>>> type([100])
<class 'list'>
>>> clist + 100
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> clist + [100]
[10, 20, 'tom', 'alice', [1, 2], 100] # 得到一个新列表
>>> clist
[10, 20, 'tom', 'alice', [1, 2]] # 不影响原列表
多重赋值和多元赋值
链式多重赋值
- 链式多重赋值:
变量1 = 变量n = 变量值
- 使用多重赋值列表时,所有列表同时指向同一个列表空间,任何一个列表改变,其它列表随着改变。
# 链式多重赋值
>>> x = y = 10 # 将10赋值给x和y
>>> x
10
>>> y
10
>>> x=11
>>> x
11
>>> y
10
# 链式多重赋值列表
>>> alist = blist = clist = [1, 2] # 将列表[1, 2]赋值给alist和blist
>>> alist
[1, 2]
>>> blist
[1, 2]
>>> clist
[1, 2]
# 链式赋值列表时,其中一个列表改变也会影响其它列表
>>> blist.append('haha')
>>> alist
[1, 2, 'haha']
>>> clist
[1, 2, 'haha']
>>> blist[-1] = 100
>>> alist
[1, 2, 100]
多元赋值
# 多元赋值
>>> a, b = 10, 'mn' # 将10和'mn', 分别赋值给a和b
>>> a
10
>>> b
'mn'
>>> c1, c2, c3, c4 = '1 m,' # 将字符串的字符赋值给变量,空格也算一个字符,变量个数与字符数一致
>>> c1
'1'
>>> c2
' '
>>> c3
'm'
>>> c4
','
>>> d, e, f = ['bob', [1,2], 25] # # 将列表中的元素赋值给变量
>>> d
'bob'
>>> e
[1, 2]
>>> f
25
>>> h, i = (100, d)
>>> h
100
>>> i
'bob'
变量互换
>>> a, b = 100, 200
>>> a, b = b, a # 将变量a和变量b的值,进行交换
>>> a
200
>>> b
100
>>> c,d = 'test',100
>>> c
'test'
>>> d
100
>>> c,d = d,c
>>> c
100
>>> d
'test'
分支结构、循环结构
- 流程结构:顺序、分支、循环。
- python中使用缩进代表层级关系,一般缩进四个空格。
if 分支语句
- 使用缩进代表层级关系,一般缩进四个空格。
- True:非0数值,
" "
,[False]
、not None
非空 - False:值为0的数字,
""
空字符串,[ ]
空列表,None
空 - 注意:
'' in '字符串'
为True - 三元表达式:
条件成立的代码 if 条件 else 条件不成立的代码
# if语句格式
if 条件1表达式: # 注意冒号
条件1成立时代码块
elif 条件2表达式: # 注意冒号
条件2成立时代码块
else: # 注意冒号
条件均不成立时代码块
# 三元表达式
条件成立的代码 if 条件 else 条件不成立的代码
# True和False的一些情形
[root@localhost day02]# vim ifdemo01.py
# 使用缩进代表层级关系
if -1 > 0:
print('yes') # 属于if语句,True才执行
print('ok') # 不属于if语句,一定执行
# 0、0.0、-0.0的值均为0,值为0的都为False
if -0.0:
print('-0.0非0,为True')
else:
print('-0.0值为0,为False')
# 空格是非空字符串,长度不为0,为True
if " ":
print('" "空格也是一个字符,为True')
# 空字符串,长度为0,为False
if "":
print('""非空字符串,为True')
else:
print('""是空字符串,为False')
# [False]非空列表,存在元素是False,为True
if [False]:
print('[False]非空列表,为True')
# 空列表,元素个数为0,为False
if [ ]:
print('[ ]非空列表,为True')
else:
print('[ ]是空列表,为False')
# None是空,为False,取反为True
if not None:
print('None为False,取反为True')
[root@localhost day02]# python3 ifdemo01.py
ok
-0.0值为0,为False
" "空格也是一个字符,为True
""是空字符串,为False
[False]非空列表,为True
[ ]是空列表,为False
None为False,取反为True
if 语句练习
# 练习:
1. 提示用户输入用户名和密码
2. 获得到相关信息后,将其保存在变量中
3. 如果用户输的用户名为 bob,密码为 123456,则输出 Login successful,否则输出 Login incorrect
[root@localhost day02]# vim iftest01.py
# 定义两个变量 username 和 password,分别从键盘获取用户名和密码
username = input('请输入用户名:')
password = input('请输入密码:')
# input()函数获取的值都是字符类型,密码要用引号引起来
if username == 'bob' and password == '123456':
print('Login successful')
else:
print('Login inorrect')
print(" Login end ")
# 练习:成绩评级
1. 如果成绩大于60分,输出“及格”
2. 如果成绩大于70分,输出“良”
3. 如果成绩大于80分,输出“好”
4. 如果成绩大于90分,输出“优秀”
5. 否则输出“你要努力了”
[root@localhost day02]# vim iftest02.py
score = int(input('分数:'))
#程序的执行,是从上往下执行的
if score < 0 or score > 100:
print('成绩不合法')
elif score >= 90:
print('优秀')
elif score >= 80:
print('好')
elif score >= 70:
print('良')
elif score >= 60:
print('及格')
else:
print('你要努力了!!!')
random.choice()
- random模块的函数
random.choice(列表或字符串)
,会随机返回列表中的一个元素或字符串中的一个字符。
# random.choice()
>>> import random
>>> random.choice('+-') # random.choice(字符串)
'+'
>>> random.choice('+-')
'-'
>>> random.choice(['+-','*']) # random.choice(列表)
'+-'
>>> random.choice(['+-','*'])
'*'
# 练习:猜拳游戏
1. 计算机随机出拳
2. 玩家自己决定如何出拳
方式一:
[root@localhost day02]# vim iftest03.py
# 导入随机数的模块random
import random
all_choices = ['石头','剪刀','布'] # 定义列表all_choices,存储出拳的每个选择
# 使用random模块的choice方法,从变量中随机选出一个元素。random两下Tab查看方法列表
computer = random.choice(all_choices) # 获取电脑的出拳选择
player = input('请出拳(石头/剪刀/布):') # 获取用户的出拳选择
print("Your choice:" + player + ", Computer's choice: " + computer) # 打印电脑和玩家的出拳选择
if player not in all_choices:
print('你的出拳选择错误')
elif player == '石头':
if computer == '石头':
print('平局')
elif computer == '剪刀':
print('You WIN!!!')
else:
print('You LOSE!!!')
elif player == '剪刀':
if computer == '石头':
print('You LOSE!!!')
elif computer == '剪刀':
print('平局')
else:
print('You WIN!!!')
else:
if computer == '石头':
print('You WIN!!!')
elif computer == '剪刀':
print('You LOSE!!!')
else:
print('平局')
方式二:
[root@localhost day02]# vim iftest04.py
import random # 导入random模块
all_choices = ['石头','剪刀','布']
# 定义列表win_list,存储玩家获胜的可能性。每个子列表中,玩家为第一个元素,电脑为第二个元素
win_list = [ ['石头','剪刀'], ['剪刀','布'], ['布','石头'] ]
computer = random.choice(all_choices) # 获取电脑随机的出拳选择
player = input('请出拳(石头/剪刀/布):') # 获取玩家的出拳选择
print("Your choice:" + player + ", Computer's choice: " + computer)
if player not in all_choices:
print('你的出拳选择错误')
elif player == computer: # 如果玩家和电脑的出拳相同,则平局
print('平局')
elif [player,computer] in win_list: # 如果列表[玩家,电脑]的在列表win_list中,则可判断玩家赢
print('You WIN!!!')
else:
print('You LOSE!!!')
while 循环语句
- 循环结构的思路:按照顺序结构写出语句,将重复使用的语句写为循环结构。
# while循环语句格式
while 条件语句:
条件成立时的循环体 # 直到条件不成立才会退出while循环。循环体中可以有迭代语句,也可以没有(可构成死循环)
# 练习:猜拳游戏,三局两胜
1. 猜拳游戏,获胜方记录胜利次数
2. 实现循环结构,要求游戏三局两胜(一方赢两局,游戏就结束)
[root@localhost day02]# vim whiletest01.py # test03_while.py是文件名,可以修改
import random
all_choices = ['石头','剪刀','布']
win_list = [['石头','剪刀'],['剪刀','布'],['布','石头']]
pwin = 0 # 记录人胜利的次数
cwin = 0 # 记录计算机胜利的次数
while pwin < 2 and cwin < 2:
computer = random.choice(all_choices)
player = input('请出拳(石头/剪刀/布):')
print("Your choice:" + player + ", Computer's choice: " + computer)
if player not in all_choices:
print('你的出拳选择错误')
elif player == computer:
print('平局')
elif [player,computer] in win_list:
pwin += 1
print('You WIN!!!')
else:
cwin += 1
print('You LOSE!!!')
break、continue、else
break
:结束所在循环。continue
:跳过本次循环,执行下一次循环的条件判断。else:
:循环正常结束时执行的语句。break会结束所在循环,所以循环没有正常结束,不会执行else语句。
# break、continue、else
# break结束所在循环
[root@localhost day02]# vim break.py
sum10 = 0
counter = 1
while counter <= 10:
if counter == 2:
break
sum10 += counter
counter += 1
print(sum10)
[root@localhost day02]# python3 break.py
1
# continue跳过本次循环
[root@localhost day02]# vim continue.py
sum10 = 0
counter = 1
while counter <= 10:
counter += 1
if counter == 2:
continue
sum10 += counter
print(sum10)
[root@localhost day02]# python3 continue.py
53
# 循环正常结束时执行的else语句。break会跳过else语句。
[root@localhost day02]# vim else.py
sum10 = 0
counter = 1
while counter <= 10:
if counter == 2:
break # break结束所在循环
sum10 += counter
counter += 1
else:
print("break & else")
print(sum10)
sum10 = 0
counter = 1
while counter <= 10:
counter += 1
if counter == 2:
continue # continue结束本次循环
sum10 += counter
else:
print("continue & else")
print(sum10)
[root@localhost day02]# python3 else.py
1
continue & else
53
random.randint()
- random模块的函数
random.randint(整数a, 整数b)
,会随机返回一个 [整数a, 整数b] 的整数。
# 练习:猜数
1. 系统随机生成 100 以内的整数
2. 要求用户猜生成的数字是多少
3. 最多猜 5 次,猜对结束程序
4. 如果5次全部猜错,则输出正确结果
[root@localhost day02]# vim randint.py
import random
number = random.randint(1,100) # randint函数,从1~100范围内,取出一个随机整数
counter = 0
while counter < 5:
answer = int(input("guess(1-100) ")) # 注意,input输入的数据类型是str
if answer == number:
print('猜对了')
break
elif answer > number:
print('猜大了')
else:
print('猜小了')
counter += 1 # 每次猜数,counter自加1
else:
print('right answer=', number)
for 循环语句
- 可迭代对象有:字符串,列表,元组,集合,字典,range(),以及其它可以被for循环的都是可迭代对象。
- 像可迭代对象这样可以存放多个元素的对象,称之为容器。
- 从容器中依次取出元素的过程叫做遍历。
# for循环语句格式
for 变量 in 可迭代对象:
for 循环逻辑
# 练习:扫描商品
[root@localhost day02]# vim fortest01.py
cart = ["巧克力派", "鱿鱼丝", "碎冰冰", "Python从入门到入坟"]
for item in cart: # item: 项
print("扫码: " + item)
[root@localhost day02]# python3 fortest01.py
扫码: 巧克力派
扫码: 鱿鱼丝
扫码: 碎冰冰
扫码: Python从入门到入坟
# 练习:商品总价
[root@localhost day02]# vim fortest02.py
cart_price = [10, 15, 20, 99.99]
total_price = 0
for price in cart_price:
total_price += price
print("总价为: " + str(total_price))
[root@localhost day02]# python3 fortest02.py
总价为: 144.99
# 遍历字符串
[root@localhost day02]# vim fortest03.py
str01 = "hello world" # 注意,空格也算一个字符
for str_item in str01:
print(str_item)
[root@python opt]# python3 fortest03.py
h
e
l
l
o
w
o
r
l
d
range()
- range() 是一个内建函数,它的返回值是整数范围。
- range函数语法:含头去尾
range(头,尾,步长)
- 注意:步长为负数时,头必须大于尾,依旧含头去尾。
range(头,尾)
:省略步长默认为1。range(尾)
:省略头默认为0。range(数字)
:共产生数字个整数。
- range函数语法:含头去尾
# range函数语法:含头去尾
range(头,尾,步长)
range(头,尾) # 省略步长默认为1
range(尾) # 省略头默认为0
>>> tmp = range(1, 10) # 含头去尾,共9个整数
>>> len(tmp)
9
>>> list(tmp)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> tmp01 = range(5)
>>> tmp01
range(0, 5)
>>> list(tmp01)
[0, 1, 2, 3, 4]
>>> tmp02 = range(1, 11, 2)
>>> list(tmp02)
[1, 3, 5, 7, 9]
>>> tmp03 = range(10, -4, -2) # 步长为负数,依旧含头去尾
>>> list(tmp03)
[10, 8, 6, 4, 2, 0, -2]
>>> type(range(0,3))
<class 'range'>
range()与for循环
- range函数经常用来控制for循环次数。
# range函数控制for循环次数
[root@localhost day02]# vim rangefor.py
for i in range(3):
print("hello world")
[root@localhost day02]# python3 rangefor.py
hello world
hello world
hello world
range()与列表
# 练习:使用for循环和range函数编写一个程序,计算有10个数字的斐波那契数列
[root@localhost day02]# vim rangefib.py
fib = [1,1] # 定义列表,指定斐波那契数列初始的两个值
for i in range(8): # for循环执行8次,列表fib增加8个元素,元素个数变为10
fib.append(fib[-1] + fib[-2]) # 列表追加,每次都是最后一个元素和倒数第二个元素相加,产生新的元素
print(fib)
# 练习:改进程序,要求用户输入一个数字(长度),可以生成用户指定长度的斐波那契数列
[root@localhost day02]# vim rangefib.py
fib = [1,1]
n = int(input('长度: '))
for i in range(n - 2): # 因为列表fib本身有两个初始值,所以要产生n-2个数字
fib.append(fib[-1] + fib[-2])
print(fib)
列表推导式
- 列表推导式(列表生成式)只是一种简写方式:
列表名=[列表元素(可以引用变量i) for i in range函数]
# 生成列表,列表元素1~10
[root@localhost day02]# vim rangelist01.py
# 传统写法
list01 = []
for i in range(1, 11): # 注意,包头去尾
list01.append(i)
print("list01", list01)
# 简写:列表推导式
list02 = [i for i in range(1, 11)]
print("list02", list02)
[root@localhost day02]# python3 rangelist01.py
list01 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list02 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 列表list02的基础上对其中的每个元素加0.1
[root@localhost day02]# vim rangelist01.py
list02 = [i+0.1 for i in range(1, 11)]
print("list02", list02)
print(type(list02[0])) # int+float=float
[root@localhost day02]# python3 rangelist01.py
list02 [1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1]
<class 'float'>
# 生成列表,列表元素10.0~10.11
[root@localhost day02]# vim rangelist02.py
# 传统写法
list03 = []
for i in range(12):
list03.append("10."+str(i))
print("list03", list03)
# 简写:列表推导式
list04 = ["10."+str(i) for i in range(12)]
print("list04", list04)
[root@localhost day02]# python3 rangelist02.py
list03 ['10.0', '10.1', '10.2', '10.3', '10.4', '10.5', '10.6', '10.7', '10.8', '10.9', '10.10', '10.11']
list04 ['10.0', '10.1', '10.2', '10.3', '10.4', '10.5', '10.6', '10.7', '10.8', '10.9', '10.10', '10.11']
# 生成5个1~100的随机数的列表
[root@localhost day02]# vim rangelist03.py
import random
list05 = []
for i in range(5):
list05.append(random.randint(1,100))
print(list05)
list06 = [random.randint(1,100) for i in range(5)]
print(list06)
[root@localhost day02]# python3 rangelist03.py
[14, 45, 91, 86, 32]
[28, 99, 71, 80, 49]
文件读写操作
open()、close()
- 在python脚本中,不管是读文件还是写文件,哪怕仅仅是打印其内容,都得先打开打文件,这样才能访问它。
- 作为打开文件之门的“钥匙”,内建函数 open() 提供了初始化输入/输出(I/O)操作的通用接口,成功打开文件后会返回一个文件对象,否则引发一个错误。后续对文件的所有读写操作都需要通过这个文件对象,而不是直接操作文件中的数据。
文件对象 = open('文件路径', mode='模式参数')
:打开文件。- 模式参数:
r
:以读方式打开(文件不存在则报错)。w
:以写方式打开(文件存在则覆盖,不存在则新建)。a
(append):以追加模式打开(必要时新建文件)。直接追加,换行需要手动换行符。b
(bit):以二进制模式打开。
- 模式参数:
- 文件对象会占用内存空间,因此使用完文件后,要关闭文件。
文件对象.close()
:关闭文件。- 如果忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问。
文件读操作
- 读取文件的步骤:open()打开文件(r模式)——》读操作——》close()关闭文件。
r
:以读方式打开(文件不存在则报错)- 读操作会将内容读取到内存中。
read()
文件对象.read(字符个数)
:读取上次读取之后的指定个数的字符。- 注意:如果文件打开模式是
rb
,则文件对象.read(字节个数)
- 注意:如果文件打开模式是
文件对象.read()
:读取上次读取之后的所有字符。
# read()
[root@python day03]# cat test.txt
abc
def
ghijkl
mnopq
rst
[root@python day03]# cat read.py
fr = open('test.txt',mode='r') # 1.打开文件,r读模式
print(fr.read(5)) # 2.读取文件,读取前5个字符,换行符\n计为一个字符
print('1')
print(fr.read(4)) # 接着向后读4个字符
print('2')
print(fr.read()) # 读取文件剩余的所有内容
print('3')
print(fr.read())
print("over")
fr.close() # 3.关闭文件
[root@python day03]# python3 read.py
abc
d
1
ef
g
2
hijkl
mnopq
rst
3
over
文件指针
- 文件指针 标记 从哪个位置开始读取数据。
- 第一次打开 文件时,通常 文件指针会指向文件的开始位置。
- 执行read函数后,文件指针 会移动到 读取内容的末尾。
- 执行
文件对象.read()
后,默认情况下会移动到 文件末尾。 - 重新打开文件时,文件指针 重新指向文件的 开始位置。
readline()
-
文件对象.readline()
:读取一行内容。 -
优点:
-
read()
会默认把文件的 所有内容 一次性读取到内存。如果文件太大,对内存的占用会非常严重。 -
readline()
一次读取一行内容,执行后,会把 文件指针 移动到下一行,准备再次读取。
-
# readline()
[root@python day03]# cat test.txt
abc
def
ghijkl
mnopq
rst
[root@python day03]# cat readline.py
fr = open('test.txt',mode='r')
print(fr.readline()) # 读取第一行数据
print('1')
print(fr.readline()) # 读取第二行数据
fr.close()
[root@python day03]# python3 readline.py
abc
# 空行的原因:读操作会读取文件的换行符,加上print自身的结束符为换行符
1
def
over
# 优化
[root@python day03]# cat readline.py
fr = open('test.txt',mode='r')
print(fr.readline(), end='') # 读取第一行数据,会读取文件的换行符
print('1')
print(fr.readline(), end='') # 读取第二行数据
print("over")
fr.close()
[root@python day03]# python3 readline.py
abc
1
def
over
readlines()
文件对象.readlines()
:读取剩余的所有行,然后把它们作为一个字符串列表返回。
# readlines()
[root@python day03]# cat test.txt
abc
def
ghijkl
mnopq
rst
[root@python day03]# cat readlines.py
fr = open('test.txt', mode='r')
data = fr.readlines()
print('1', data[0])
print('2', data[1])
print('over')
fr.close()
[root@python day03]# python3 readlines.py
1 abc
2 def
over
# 优化
[root@python day03]# cat readlines.py
fr = open('test.txt', mode='r')
data = fr.readlines()
print('1', data[0], end='')
print('2', data[1], end='')
print('over')
fr.close()
[root@python day03]# python3 readlines.py
1 abc
2 def
over
# 可以遍历文件对象.readlines()
[root@python day03]# cat readlines02.py
fr = open('test.txt', mode='r')
for data in fr.readlines():
print(data, end='')
fr.close()
[root@python day03]# python3 readlines.py
abc
def
ghijkl
mnopq
rst
读取大文件
- 如果要读取一个大文件(1TB),无论是
cat
还是read()
还是readline()
,都会一次性将1TB读取到内存,撑爆内存。 - 大文件可以使用
readline()
逐行读取,每读一行内存加载一行,下一次读取释放上一次的内存。也可以使用read(字符数或字节数)
。
# readline()逐行读取大文件
[root@python day03]# cat readbig.py
fr = open('test.txt', mode='r')
while True: # 死循环
data = fr.readline() # 读取一行数据
if len(data) == 0: # 文件读取完毕,终止循环。注意,空行的换行符计为一个字符。
break
print("data:", data, end="") # 输出一行
fr.close()
[root@python day03]# python3 readbig.py
data: abc
data: def
data: ghijkl
data: mnopq
data: rst
文件写操作
- 写入文件的步骤:open()打开文件(w模式)——》写操作——》close()关闭文件。
w
:以写方式打开(文件存在则覆盖,不存在则新建)。
write()
- write方法把含有 文本数据 或 二进制数据 的内容写入到文件中去。
文件对象.write('文本数据或二进制数据')
# write()
[root@python day03]# cat write.py
fw = open("tw.txt", mode="w") # w模式,文件不存在则新建
fw.write("hello world\n") # 手动写入换行符\n
fw.write("you are my sunshine~\n")
fw.close()
fw = open("tw.txt", mode="w") # 文件存在则覆盖
fw.write("you are my sunshine~\n")
fw.write("hello world\n")
fw.close()
[root@python day03]# python3 write.py
[root@python day03]# cat tw.txt
you are my sunshine~
hello world
writelines()
- 和readlines函数 一样,writelines函数是针对 列表 的操作,它接受一个 字符串列表 作为参数,将他们写入文件。
- 通过writelines函数将列表写入文件,元素与元素之间首尾相连,没有分隔符,没有换行符。
文件对象.writelines('列表')
# write()
[root@python day03]# cat writelines.py
list01 = ["hello\n", "world\n"] # 手动写入换行符\n
list02 = ["you", "are\n", "my ", "sunshine\n"] # 手动写入空格分隔
fw1 = open("twls.txt", mode="w") # 文件不存在则新建
fw1.writelines(list01)
fw1.writelines(list02)
fw1.close()
fw1 = open("twls.txt", mode="w") # 文件存在则覆盖
fw1.writelines(list02)
fw1.writelines(list01)
fw1.close()
[root@python day03]# python3 writelines.py
[root@python day03]# cat twls.txt
youare
my sunshine
hello
world
文件的复制 rb、wb
- 文件的复制就是一读一写。普通文件的底层也是二进制文件,因此使用模式
rb
和wb
来复制二进制文件。rb
读取字节不能使用readline函数,使用文件对象.read(字节个数)
# 文件的复制
[root@python day03]# cat copy.py
fr = open('/usr/bin/ls', mode='rb')
fw = open('myls', mode='wb')
while True:
data = fr.read(4096) # 以4KB或其倍数读取
if len(data) == 0: # 文件读取完毕则退出循环
break
fw.write(data) # 将读取到的数据写入目标文件
fr.close()
fw.close()
[root@python day03]# python3 copy.py
[root@python day03]# ls -lh /usr/bin/ls
-rwxr-xr-x 1 root root 140K Jan 18 2023 /usr/bin/ls # 140K/4K=35次,可以根据实际情况调节读取的字节数
[root@python day03]# ls -lh myls
-rw-r--r-- 1 root root 140K Oct 6 17:32 myls # 与源文件大小一致
with语句
- with语句是用来简化代码的:在将打开文件的操作放在 with 语句中,代码块结束后,文件将自动关闭。
- 读写文件的逻辑没有变化,变的只是写法。
with open('文件路径', mode='模式参数') as 文件对象:
# with语句的格式
with open('文件路径', mode='模式参数') as 文件对象: # 注意语句结尾的`:`
读写操作
# 文件的复制(with语句简写)
[root@python day03]# cat with.py
with open('/usr/bin/ls', mode='rb') as fr:
with open('myls2', mode='wb') as fw:
while True:
data = fr.read(4096)
if len(data) == 0:
break
fw.write(data)
[root@python day03]# python3 with.py
[root@python day03]# ls -lh /usr/bin/ls
-rwxr-xr-x 1 root root 140K Jan 18 2023 /usr/bin/ls
[root@python day03]# ls -lh myls2
-rw-r--r-- 1 root root 140K Oct 6 18:52 myls2
函数
- 函数:把具有独立功能的代码块组织为一个小模块,在需要的时候调用。
形参和实参
- 函数名、参数名的命名规则:可以由大小写字母、数字、下划线组成,不能以数字开头,不能与关键字重名。
- 形参和实参:
- 形参:定义函数时,小括号中的参数。是用来接收数据用的,在函数内部作为变量使用。
- 实参:调用函数时,小括号中的参数。是用来传递数据到函数内部使用。
- 多个参数之间用
,
分隔。 - 调用函数时,实参的个数需要和形参一致,每个实参对应相同位置的形参。
- 多个参数之间用
# 格式
# 定义函数
def 函数名(形参列表): # 形参列表是可选的,多个形参用`,`分隔
"""函数说明的文档字符串"""
函数封装的代码块
# 调用函数
函数名(实参列表) # 实参一一对应函数的形参,使用`,`分隔
# 示例
# 定义函数
>>> def washing_machine(something):
... print("打水")
... print("加洗衣粉!!!")
... print("洗" + something)
... print("甩干")
...
>>> washing_machine
<function washing_machine at 0x7fec9118b158>
# 调用函数
>>> washing_machine("衣服")
打水
加洗衣粉!!!
洗衣服
甩干
>>> washing_machine("床单")
打水
加洗衣粉!!!
洗床单
甩干
默认参数、位置参数、关键字参数
-
默认参数:给形参赋予一个默认值,当形参没有被赋予实参时,形参使用默认值。
- 注意:定义函数时,默认参数一定放在没有默认值的形参的后面。
def 函数名(形参1, 形参2, 形参3=默认值, 形参4=默认值):
- 注意:定义函数时,默认参数一定放在没有默认值的形参的后面。
-
实参的传参方式:位置传参、关键字传参
- 位置传参:实参不指定形参传参,默认按照参数列表顺序传参。这种实参叫位置参数。
- 关键字传参:实参指定形参传参,可以不按照参数列表顺序传参。这种实参叫关键字参数。
- 注意:实参赋值时,关键字参数一定要写在所有位置参数后面。
# 默认参数
>>> def get_sum(num01, num02=100):
... print(num01, num02)
...
>>> get_sum(50) # num01=50 num02=100
50 100
>>> get_sum(10, 20) # num01=10 num02=20
10 20
>>> def get_sum1(num01=30, num02=40):
... print(num01, num02)
...
>>> get_sum1()
30 40
>>> def get_sum2(num01=30, num02): # 报错,定义函数时,默认参数一定放在没有默认值的形参后面
... print(num01, num02)
...
File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
# 默认参数、位置参数、关键字参数
>>> def get_info(name, age=20, gender='female'):
... print(f'name={name}, age={age}, gender={gender}')
...
# 默认参数:给形参赋予一个默认值,当形参没有被赋予实参时,形参使用默认值
>>> get_info('nfx') # name=nfx, age=20, gender=female
>>> get_info('nfx', 18) # name=nfx, age=18, gender=female
# 位置传参:实参不指定形参传参,默认按照参数列表顺序传参。这种实参叫位置参数。
>>> get_info('nfx', 18, 'male') # name=nfx, age=18, gender=male
>>> get_info(18, 'male', 'nfx') # name=18, age=male, gender=nfx
# 关键字传参:实参指定形参传参,可以不按照参数列表顺序传参。这种实参叫关键字参数。
>>> get_info(name='nfx', age=18) # name=nfx, age=18, gender=female
>>> get_info(age=18, name='nfx') # name=nfx, age=18, gender=female
# 关键字参数后不能有位置参数
>>> get_info('nfx') # name=nfx, age=20, gender=female
>>> get_info('nfx', gender='male') # name=nfx, age=20, gender=male
>>> get_info(name='nfx', gender='male') # name=nfx, age=20, gender=male
>>> get_info(name='nfx', 20) # 报错,关键字参数后面不能有位置参数
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
>>> print('hello', 'world', sep='---', end='!!\n') # hello---world!!
>>> print('hello', sep='---', 'world', end='!!\n') # 报错,关键字参数后面不能有位置参数
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
f’'、str.format()、str%()
# f''、str.format()和str%()格式化表达式增加描述的字符
>>> sr1='abc'
>>> k1=len(sr1)
>>> print(f'字符串{sr1}的长度是{k1}') # f''
字符串abc的长度是3
>>> print('字符串{0}的长度是{1}'.format(sr1,k1)) # str.format()
字符串abc的长度是3
>>> print('字符串%s的长度是%d'%(sr1,k1)) # str%()
字符串abc的长度是3
脚本的位置参数、sys.argv列表
- 类似于shell脚本的位置变量,运行python脚本时,可以在python脚本后写上脚本的位置参数,使用空格分隔。在python脚本中使用sys模块的属性
sys.argv
来接收脚本的位置参数。sys.argv
是一个列表:索引0的元素sys.argv[0]
是程序或脚本名,索引1的元素sys.argv[1]
是python脚本的第1个位置参数,索引2的元素sys.argv[2]
是python脚本的第二个位置参数,……- shell脚本的位置变量:
$0
是程序或脚本名,$1
是第一个位置变量,$2
是第二个位置变量,…… - 注意:列表
sys.argv
的元素是字符串类型。
- shell脚本的位置变量:
# Python脚本的位置参数、sys.argv
[root@python day03]# cat location.py
import sys
print(sys.argv[2]) # sys模块的列表argv的索引2是python脚本的第二个位置参数
print(sys.argv[0]) # sys模块的列表argv的索引0是python脚本的脚本名
print(sys.argv[1]) # sys模块的列表argv的索引1是python脚本的第一个位置参数
[root@python day03]# python3 location.py 1 2 3
2
location.py
1
# 练习:斐波那契数列
[root@python day03]# cat lo01.py
import sys
def fib(n):
fiblist = [1, 1]
for i in range(n-2):
fiblist.append(fiblist[-1] + fiblist[-2])
print(fiblist)
fib(int(sys.argv[1])) # 列表 `sys.argv` 的元素是字符串类型,需要转换为int
[root@python day03]# python3 lo01.py 7
[1, 1, 2, 3, 5, 8, 13]
# 练习:复制文件
[root@python day03]# cat lo02.py
import sys
def copy(src, dest):
with open(src, mode='rb') as fr:
with open(dest, mode='wb') as fw:
while 1:
data = fr.read(4096)
if len(data) == 0:
break
fw.write(data)
copy(sys.argv[1], sys.argv[2])
[root@python day03]# python3 lo02.py /usr/bin/ls myls3
[root@python day03]# ll /usr/bin/ls
-rwxr-xr-x 1 root root 143296 Jan 18 2023 /usr/bin/ls
[root@python day03]# ll myls3
-rw-r--r-- 1 root root 143296 Oct 6 20:59 myls3
return语句
return 返回值
:表示所在函数执行结束,并返回给调用者一个返回值。- return语句表示所在函数执行结束,因此该函数后续的代码都不会被执行。
- 如果函数没有使用return语句,相当于
return None
,返回None。调用该函数赋值给变量,则None为字符串。 - 返回值可以是变量,也可以是公式。
[root@python day03]# cat return01.py
def re():
return None
print(type(re())) # 返回的是`None`,而不是字符串`'None'`
print(type(None))
print(type('None'))
[root@python day03]# python3 return01.py
<class 'NoneType'>
<class 'NoneType'>
<class 'str'>
[root@python day03]# cat return02.py
def re():
print('re') # 没有使用return语句相当于`return None`
def et():
print('et')
return None # 返回None。注意`none`不是`None`
def ts():
print('ts')
return 'none' # 返回字符串
def st():
print('st')
return 1
a = re();print(a)
b = et();print(b)
c = ts();print(c)
d = st();print(d)
[root@python day03]# python3 return02.py
re
None
et
None
ts
none
st
1
# 练习:斐波那契数列的结果使用return语句返回
[root@python day03]# cat returnfib.py
import sys
def fib(n):
fiblist = [1, 1]
for i in range(n-2):
fiblist.append(fiblist[-1] + fiblist[-2])
return fiblist
print('over') # return语句所在函数的后续代码都不会被执行
for i in range(3, 1, -1):
print(fib(int(sys.argv[i])))
[root@python day03]# python3 returnfib.py 5 6 7
[1, 1, 2, 3, 5, 8, 13]
[1, 1, 2, 3, 5, 8]
匿名函数 lambda函数
- Python 允许用 lambda 关键字创造匿名函数(也叫lambda函数),匿名函数不需要使用标准的def方式声明。
- 一个完整的 lambda '语句’代表了一个表达式,这个表达式的定义体必须和声明放在同一行。
- 定义匿名函数:
变量名 = lambda 形参1, 形参n: return语句
- 定义匿名函数,匿名函数必须有返回值。
- 这里的变量名就是匿名函数的函数名,所以本质上函数名就是一个变量。
- 调用匿名函数:
变量名(实参列表)
# 匿名函数(lambda函数)
# def方式
>>> def add(x, y):
... return x+y
...
>>> print(add(100, 200))
300
# 定义匿名函数,匿名函数必须有返回值
>>> test = lambda x,y: x+y # `变量名 = lambda 形参1, 形参n: return语句`
# 调用匿名函数
>>> print(test(100, 200))
300
>>> print(add)
<function add at 0x7fec91190730> # 函数类型function
>>> print(test)
<function <lambda> at 0x7fec911907b8> # 函数类型function
# 可以看出:变量test是一个匿名函数的函数名,所以本质上函数名就是一个变量
# def方式
>>> def func01(num):
... return True if num % 2 ==1 else False # if表达式的简写
...
# if num % 2 == 1:
# return True
# else:
# return False
>>> print(func01(99))
True
# 匿名函数方式
>>> test01 = lambda num: True if num % 2 == 1 else False
>>> print(test01(99))
True
全局变量、局部变量、global
- 变量根据作用域分为全局变量和局部变量。
- 全局变量对脚本中所有函数生效。局部变量只在单个函数内部生效。
- 函数内使用全局变量:
- 函数内使用全局变量时,会默认定义一个新的同名局部变量,对该同名局部变量进行操作,而不是对全局变量进行操作。
- 如果想要在函数内操作全局变量,则**需要先使用关键字global来进行宣告:
global 全局变量名
**。- 注意:不能在定义了同名局部变量之后宣告使用全局变量。
- global也可以定义全局变量,即定义新的全局变量。
- 注意:使用global宣告新的全局变量后要赋值才真正定义了。
# 函数内,默认定义一个新的同名局部变量,对该同名局部变量进行操作,而不是对全局变量进行操作
>>> x = 10
>>> def func():
... x = 20
... print(x)
...
>>> func()
20
>>> x
10
# 需要先使用 `global 全局变量名` 来进行宣告,才能操作全局变量
>>> y = 60
>>> def funct():
... global y
... y = 70
... print(y)
...
>>> funct()
70
>>> y
70
# 不能在定义了同名局部变量之后宣告使用全局变量
>>> z = 80
>>> def functi():
... z = 90
... global z
... print(z)
...
File "<stdin>", line 3
SyntaxError: name 'z' is assigned to before global declaration # 报错:在宣告使用全局变量前定义了同名局部变量
# global也能定义全局变量
>>> def functio():
... global m
... m = 7
... print(m)
...
>>> functio()
7
>>> m
7
# 使用global宣告新的全局变量后要赋值才真正定义了
>>> def functo():
... global n
...
>>> n
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'n' is not defined
PyCharm
- PyCharm是由JetBrains公司开发的一款集成开发环境(IDE)软件。
- PyCharm官网:https://www.jetbrains.com.cn/pycharm/download
- 安装:在官网下载安装程序,双击运行安装,注意勾选"Add launchers dir to the PATH"
// 新建项目
New Project:
——》Location选择非C盘就行
——》Python Interpreter选择已存在的解释器"Previously configured interpreter",没有选项则添加"Add Interpreter"
——》选择"System Interpreter",选择python的安装目录,"OK"
——》Create
// 代码缩进
向右缩进:Tab
向左缩进:Shift+Tab
单行代码缩进:在开头缩进
多行代码缩进:选中多行代码直接缩进
// 选中
Ctrl+W 选中,每按一次扩选一次
Ctrl+Shift+W 收缩,每按一次收缩一次
// 注释
注释/解除注释:Ctrl+/
// 查看模块
import 模块名,这时Ctrl+单击模块名,可以跳转该模块的脚本文件`模块名.py`
Linux版本的PyCharm的底下,有"Terminal"按钮,是一个内置的终端。
// 复制删除
复制并粘贴所选行:Ctrl+D
删除所选行:Ctrl+Y
// 移动
移动所选行或光标行:Alt+Shift+上下键
移动整个方法:光标在方法标头处,Ctrl+Shift+上下键
// 可读性
收起光标所在方法:Ctrl+-
展开光标所在方法:Ctrl+=
收起所有方法:Ctrl+Shift+-
展开所有方法:Ctrl+Shift+=
// 包围和解包
包围:Ctrl+Alt+T,选择包围方式
解包:Ctrl+Shift+Delete,选择解包方式
// 快速ifname
输入main后回车
pickle模块
- pickle模块是Python中用于对象持久化的一种方式,通过将对象转化为字节流进行存储和读取。
- dump函数用于将对象转化为字节流并写入文件。
- load函数用于从文件中读取数据并重构出对象。
# pickle模块
[root@python day03]# cat pickletest.py # 注意:python库中已有文件pickle.py
import pickle as p
writefile = 'shoplist.data'
shoplist = ['apple', 'mango', 'carrot']
with open(writefile, mode='wb') as fw:
p.dump(shoplist, fw) # dump函数用于将对象转化为字节流并写入文件
with open(writefile, mode='rb') as fr:
readfile = p.load(fr) # load函数用于从文件中读取数据并重构出对象
print(readfile)
[root@python day03]# python3 pickletest.py
['apple', 'mango', 'carrot']
模块基础
- 模块可以实现代码的重用,导入模块,就可以使用模块中已经定义好的类,函数和变量,减少代码的冗余性。
- 文件是物理上组织的代码的形式,模块是逻辑上组织的代码的形式。
- 一个文件被看作是一个独立模块,一个模块也可以被看作是一个文件。
- 模块的文件名就是
模块名.py
。
导入模块 import
-
使用模块的方式:
-
方式一:导入整个模块:
import 模块名
- 调用模块属性通过
模块名.属性
- 调用模块函数通过
模块名.函数()
- 调用模块属性通过
-
方式二:导入属性或函数:
from 模块名 import 属性名或函数名
-
-
使用别名:
import 模块名 as 别名
from 模块名 import 属性名或函数名 as 别名
-
导入多个模块:
- 可以一行导入一个模块:
import 模块名
- 也可以一行导入多个模块:
import 模块名1,模块名2,模块名n
- 可以一行导入一个模块:
-
python脚本中可以导入自定义模块,直接导入则二者需要放在同一目录下:
import 自定义模块名
# 使用模块的方法
>>> import random # 导入整个模块
>>> random.randint(1,3)
3
>>> from random import randint # 导入属性或函数
>>> randint(1,3)
3
# 使用别名
>>> import random as r
>>> r.randint(1,3)
2
>>> from random import randint as ri
>>> ri(1,3)
3
搜索路径 sys.path
- 模块的导入需要一个路径搜索的过程,搜索的路径保存sys模块的path变量中。
- 变量
sys.path
是一个列表,包含了解释器搜索模块的路径。当导入一个模块时,Python解释器会按照sys.path
列表中的路径按顺序进行搜索,直到找到要导入的模块为止。列表包含的元素主要有:- 当前脚本所在目录
''
(优先级第一) - 系统环境变量
PYTHONPATH
中指定的目录(优先级第二,该环境变量默认不存在) - 系统的Python标准库目录
- 安装第三方库的目录
- 当前脚本所在目录
- 修改搜索路径的方式:
- 列表直接添加新元素,insert函数、append函数等,但只对当前解释器进程有效。
- 修改环境变量:
PYTHONPATH = '路径'
。环境变量PYTHONPATH的优先级第二。
# 搜索路径
[root@python ~]# python3
Python 3.6.8 (default, Apr 12 2022, 06:55:39) # 当前python版本,也可以使用`python -V`查看
[GCC 8.5.0 20210514 (Red Hat 8.5.0-10)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path # path, 查看python搜索模块时的默认查找路径。`''`表示当前目录
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages']
# 导入模块是根据sys.path列表元素按顺序搜索的
[root@python ~]# mkdir /tmp/mylibs
[root@python ~]# cat /tmp/mylibs/pathtest.py # 自定义模块pathtest
def hehe():
print('Hello world~')
[root@python ~]# cat /tmp/mylibs/random.py # 自定义模块random
def hehe():
print('Hello world~')
[root@python ~]# python3
>>> import pathtest # 报错,当前路径/root下没有pathtest.py
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'pathtest'
>>> import random
>>> random.hehe() # 报错,/usr/lib64/python3.6/random.py中没有函数hehe()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'random' has no attribute 'hehe'
[root@python ~]# cd /tmp/mylibs/
[root@python mylibs]# python3
>>> import pathtest # 成功导入自定义模块pathtest
>>> pathtest.hehe()
Hello world~
>>> import random # 按顺序优先导入当前目录的random.py
>>> random.hehe()
Hello world~
# 修改搜索路径
# 方式一:列表直接添加新元素,只对当前解释器进程有效
[root@python ~]# python3
>>> import sys
>>> sys.path
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages']
>>> sys.path.append('/tmp/mylibs') # 只对当前解释器进程有效
>>> sys.path
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages', '/tmp/mylibs']
>>> sys.path.insert(2,'/tmp/mylibs') # 只对当前解释器进程有效
>>> sys.path
['', '/usr/lib64/python36.zip', '/tmp/mylibs', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages', '/tmp/mylibs']
[root@python ~]# python3
>>> import sys
>>> sys.path
['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages']
# 方式二:修改环境变量PYTHONPATH,优先级第二。
[root@python ~]# export PYTHONPATH=/tmp/mylibs # export只对当前终端临时生效,写入配置文件永久生效
[root@python ~]# python3
>>> import sys
>>> sys.path
['', '/tmp/mylibs', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', '/usr/lib64/python3.6/lib-dynload', '/usr/lib64/python3.6/site-packages', '/usr/lib/python3.6/site-packages']
>>> import random
>>> random.hehe()
Hello world~
变量__name__
- 运行python脚本,会自动将导入的模块加载运行一遍。因此如果是自定义模块,可以使用预定义变量
__name__
给函数加一个身份校验。- 模块被加载时,会自动执行代码,因此要习惯把函数放入模块的顶层,把测试语句放在ifname语句之中。
- ifname语句
if __name__ == "__main__":
的快捷键:键入main后按Tab键。 - 在自定义模块中调用变量
__name__
:- 当模块脚本直接执行时,
__name__
的值为__main__
。 - 当模块被另一个脚本导入时,
__name__
的值就是该模块的名字模块名
。
- 当模块脚本直接执行时,
- 运行python脚本,对于其导入的模块A来说,无论它被导入多少次,只会被加载一次。
- 只加载一次,可以防止多重导入时代码被多次执行。
- 只加载一次,可以防止两个文件相互导入无限的相互加载。
在自定义模块中调用与定义变量__name__
当模块脚本直接执行时,__name__的值为`__main__`
当模块被另一个脚本导入时,__name__的值就是该模块的名字`模块名`
运行python脚本,对于其导入的模块A来说,无论它被导入多少次,只会被加载一次
# 准备python脚本
# import01.py文件
print('import01')
# import02.py文件
import import01 # mport02.py导入import01.py
print('import02')
def te():
print('test__name_:', __name__)
if __name__ == '__main__':
te()
print('__name__:', __name__)
# import03.py文件
import import04 # import03.py导入import04.py
print('import03')
# import04.py文件
import import03 # import04.py导入import03.py
print('import04')
# import05.py文件
import import01,import02,import03,import04 # import05.py导入import01~4.py
# 验证`__name__`和`加载次数`
# 运行import02.py文件
import01 # 导入模块时加载了一次import01
import02
test__name_: __main__
__name__: __main__
# 运行import05.py文件
import01 # 导入模块import01,加载import01
import02 # 导入模块import02,加载import02,但不再次加载import02导入的import01
__name__: import02 # 由于import05加载import02,变量`__name__`的值为`import02`,因此不执行te()函数
import04 # 导入模块import03,加载import03,并加载import03导入的import04
import03
由于导入import03时已加载import04,所以import05导入模块import04时不会再加载一次import04
import03和import04相互导入,但import05只加载先导入的模块
string模块
- string模块的常量:digits值
'0123456789'
,ascii_letters的值'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
。
>>> import string
>>> import random
>>> string.digits
'0123456789'
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> random.choice(string.digits + string.ascii_letters)
'1'
# 练习:随机密码
1. 编写一个能生成 8 位随机密码的函数,使用random模块的choice函数随机取出字符(大小写字母数字)
2. 用户可以自己决定生成多少位的密码
3. 如果不指定位数,默认8位
import random
import string
def get_pwd(n=8):
sec = ""
for i in range(n):
sec += random.choice(string.digits + string.ascii_letters)
return sec
if __name__ == '__main__':
print(get_pwd())
print(get_pwd(10))
# 运行结果
14xgay8O
R52pIcZZOJ
time模块
时间戳、结构化时间
- 时间戳 timestamp:表示的是从 1970 年1月1日 00:00:00 开始按秒计算的偏移量,单位为秒数。
- 结构化时间(struct_time): 结构化时间是一个序列,由 9 个元素组成。
- UTC世界协调时(Coordinated Universal Time)与GMT格林威治天文时间几乎相等。
- 注意:Python的time类型是不可变类型,所有的时间值都只读,不能改。
结构化时间的9个元素的属性 | 索引 | 取值区间范围 |
---|---|---|
tm_year(年) | 0 | xxxx,比如 2021 |
tm_mon(月) | 1 | 1 - 12 |
tm_mday(日) | 2 | 1 - 31 |
tm_hour(时) | 3 | 0 - 23 |
tm_min(分) | 4 | 0 - 59 |
tm_sec(秒) | 5 | 0 - 59 |
tm_wday(周几的索引) | 6 | 0 - 6(0表示周一,6表示周日) |
tm_yday(一年中的第几天) | 7 | 1 - 366 |
tm_isdst(是否是夏令时) | 8 | 0为否,1为是,-1未知。默认为-1 |
>>> import time
>>> time.time() # 获取当前系统时间的时间戳
1697092087.568863
>>> time.gmtime() # 获取当前系统时间的结构化时间(UTC时区)
time.struct_time(tm_year=2023, tm_mon=10, tm_mday=12, tm_hour=6, tm_min=28, tm_sec=18, tm_wday=3, tm_yday=285, tm_isdst=0)
>>> time.localtime() # 获取当前系统时间的结构化时间(系统设置的时区)
time.struct_time(tm_year=2023, tm_mon=10, tm_mday=12, tm_hour=14, tm_min=28, tm_sec=24, tm_wday=3, tm_yday=285, tm_isdst=0)
# Python的time类型是不可变类型,所有的时间值都只读,不能改
>>> t = time.localtime()
>>> t.tm_mon
10
>>> t.tm_mon = 2 # 报错。不能修改结构化时间的属性
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
time 模块主要函数
sleep(秒数)
time.sleep(秒数)
:用来睡眠或者暂停程序t秒,t可以是浮点数或整数。
[root@python day04]# vim time01.py
import time
def banzhuan():
print("start...")
time.sleep(3) # time.sleep(秒数)用来睡眠或者暂停程序t秒
print("end...")
banzhuan()
[root@python day04]# python3 time01.py
start...
end...
time()
time.time()
:获取当前系统时间戳(1970-1-1至今的秒数)。- 时间戳可以做算术运算。
[root@python day04]# vim time02.py
import time
print(time.time()) # time.time()返回当前系统时间戳
start_time = time.time()
end_time = time.time()
print("耗时:", end_time-start_time)
[root@python day04]# python3 time02.py
1697082679.0622306
耗时: 7.152557373046875e-07
gmtime(时间戳)、localtime(时间戳)、mktime(结构化时间)
- 将时间戳转换为结构化时间:
time.gmtime(时间戳)
(GMT):将一个时间戳转换为UTC时区的结构化时间。
time.localtime(时间戳)
:将一个时间戳转换为当前时区的结构化时间。- 省略参数时间戳则默认为
time.time()
。 - 两个函数用法一样。调用部分的值的方式:索引、切片、属性
- 省略参数时间戳则默认为
- 将结构化时间转换为时间戳:
time.mktime(结构化时间)
:将结构化时间转换为时间戳。
# time.gmtime(时间戳)、time.localtime(时间戳)
[root@python day04]# vim time03.py
import time
print("UTC时区")
t1 = time.gmtime() # 默认为time.gmtime(time.time())
print("时间戳转结构化时间:", t1)
print(type(t1))
print("索引:", t1[3], t1[4], t1[5]) # 索引。年份 月份 日
print("切片:", t1[3:6]) # 切片。(年份 月份 日)
print("属性:", t1.tm_hour, t1.tm_min, t1.tm_sec) # 属性。时 分 秒
print("")
print("当前时区")
t2 = time.localtime() # 默认为time.gmtime(time.time())
print("时间戳转结构化时间:", t2)
print("索引:", t2[3], t2[4], t2[5])
print("切片:", t2[3:6])
print("属性:", t2.tm_hour, t2.tm_min, t2.tm_sec)
print("")
print("时间戳支持计算,时间戳加3600秒")
t3 = time.localtime(time.time()+60*60) # 当前时间戳+3600秒
print("属性:", t3.tm_hour, t3.tm_min, t3.tm_sec)
[root@python day04]# python3 time03.py
UTC时区
时间戳转结构化时间: time.struct_time(tm_year=2023, tm_mon=10, tm_mday=12, tm_hour=5, tm_min=8, tm_sec=22, tm_wday=3, tm_yday=285, tm_isdst=0) # 周四tm_wday为3
<class 'time.struct_time'>
索引: 5 8 22
切片: (5, 8, 22)
属性: 5 8 22 # UTC时区小时5
当前时区
时间戳转结构化时间: time.struct_time(tm_year=2023, tm_mon=10, tm_mday=12, tm_hour=13, tm_min=8, tm_sec=22, tm_wday=3, tm_yday=285, tm_isdst=0)
索引: 13 8 22
切片: (13, 8, 22)
属性: 13 8 22 # 当前时区小时13
时间戳支持计算,时间戳加3600秒
属性: 14 8 22 # 时间戳加3600秒小时14
# time.mktime(结构化时间)
[root@python day04]# vim time04.py
import time
t3a = time.mktime(time.gmtime())
t3b = time.mktime(time.localtime())
print("结构化时间转时间戳:", t3a, t3b)
print("当前时间戳:", time.time())
[root@python day04]# python3 time04.py
结构化时间转时间戳: 1697066841.0 1697095641.0
当前时间戳: 1697095641.9405367
格式化时间字符串
- 格式化时间字符串是将时间转换为特定格式的字符串表示。可以使用格式符
%大小写字母
来指代具体的时间字符串,可以使用字符修饰。- 格式化时间字符串支持使用多种字符和空格修饰,例如:!@#$%^&*_-+=|
- 例如,
2000-10-09 20:15:16
格式符 | 含义 | 格式符 | 含义 |
---|---|---|---|
%Y | 年份(xxxx) | %w | 周几(0 - 6,星期天为0) |
%y | 去掉世纪的年份(00 - 99) | %A | 星期名全称 |
%m | 月份(01 - 12) | %a | 星期简称 |
%d | 日(01 - 31) | %B | 月份全称 |
%H | 时(24小时制,00 - 23) | %b | 月份简称 |
%I | 时(12小时制,01 - 12) | %c | 日期和时间 |
%M | 分(00 - 59) | %x | 日期 |
%S | 秒(00 - 59) | %X | 时间 |
%U | 一年中的星期数(00 – 53,星期日是一个星期的开始) | %p | 上午AM、下午PM |
%j | 一年中的天数(001 - 366) | %Z | 时区的名字 |
strftime('时间格式' [, 结构化时间])
、strptime('时间字符串', '对应的时间格式')
time.strftime('时间格式' [, 结构化时间])
(format):将结构化时间转换为格式化字符串。- 省略结构化时间默认传入
time.localtime()
,即当前的结构化时间
- 省略结构化时间默认传入
time.strptime('时间字符串', '对应的时间格式')
(parse):将格式化字符串转换为结构化时间。- 时间字符串要和时间格式一一对应:
- 取值区间范围对应。
- 分隔符对应。
- 时间字符串要和时间格式一一对应:
[root@python day04]# vim time05.py
import time
print("结构化时间:", time.localtime())
print("")
# time.strftime(时间格式 [, 结构化时间])
t4 = time.strftime("%Y%m-%d %H:%M:%S") # 默认为time.strftime(时间格式, time.localtime())
print("结构化时间转格式化时间字符串:", t4)
print("")
# time.strptime(时间字符串, 对应的时间格式),区间范围对应,分隔符对应
t5 = time.strptime("2099-06-09 13:13:13", "%Y-%m-%d %H:%M:%S")
print("格式化字符串转结构化时间:", t5)
t6 = time.strptime("2011!12!12", "%Y!%m!%d")
print("格式化字符串转结构化时间:", t6)
[root@python day04]# python3 time05.py
结构化时间: time.struct_time(tm_year=2023, tm_mon=10, tm_mday=12, tm_hour=14, tm_min=53, tm_sec=28, tm_wday=3, tm_yday=285, tm_isdst=0)
结构化时间转格式化时间字符串: 202310-12 14:53:28
格式化字符串转结构化时间: time.struct_time(tm_year=2099, tm_mon=6, tm_mday=9, tm_hour=13, tm_min=13, tm_sec=13, tm_wday=1, tm_yday=160, tm_isdst=-1)
格式化字符串转结构化时间: time.struct_time(tm_year=2011, tm_mon=12, tm_mday=12, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=346, tm_isdst=-1)
# 格式化时间字符串的格式符
>>> time.strftime("%Y %m %d %H %M %S")
'2023 10 12 15 01 34'
>>> time.strftime("%y") # 去世纪的年份
'23'
>>> time.strftime("%H %I") # 24时制、12时制
'15 03'
>>> time.strftime("%w") # 周四为4
'4'
>>> time.strftime("%U %j") # 一年中的星期数、天数
'41 285'
>>> time.strftime("%A %a")
'Thursday Thu'
>>> time.strftime("%B %b")
'October Oct'
>>> time.strftime("%c")
'Thu Oct 12 15:05:38 2023'
>>> time.strftime("%x")
'10/12/23'
>>> time.strftime("%X")
'15:05:49'
>>> time.strftime("%Z") # 时区
'CST'
>>> time.strftime("%p") # 上午AM,下午PM
'PM'
>>> time.strftime("%p !@#$%^&*_-+=|abc123 %p")
'PM !@#$%^&*_-+=|abc123 PM'
时间的比较
- 时间戳可以比较大小,秒数越大的越大。
- 结构化时间可以比较大小,越靠后的越大。
import time
>>> ta = time.time()
>>> tb = time.time()
>>> ta > tb
False
>>> ta < tb
True
>>> print(ta, tb)
1697094812.7390375 1697094817.3957717
>>> tc = time.localtime(ta)
>>> td = time.localtime(tb)
>>> tc > td
False
>>> tc < td
True
>>> print(tc ,"\n", td, sep='')
time.struct_time(tm_year=2023, tm_mon=10, tm_mday=12, tm_hour=15, tm_min=13, tm_sec=32, tm_wday=3, tm_yday=285, tm_isdst=0)
time.struct_time(tm_year=2023, tm_mon=10, tm_mday=12, tm_hour=15, tm_min=13, tm_sec=37, tm_wday=3, tm_yday=285, tm_isdst=0)
时间格式的转换
Python的三种类型时间格式,可以互相进行转换
从 | 到 | 方法 |
---|---|---|
时间戳 | UTC结构化时间 | gmtime(时间戳) |
时间戳 | 本地结构化时间 | localtime(时间戳) |
结构化时间 | 时间戳 | mktime(结构化时间) |
结构化时间 | 格式化时间字符串 | strftime(时间格式 [, 结构化时间]) |
格式化字符串 | 结构化时间 | strptime(时间字符串, 对应的时间格式) |
查看指定时间的日志
# 练习:取出2030-01-02 9点~12点的日志
[root@localhost ~]# vim /opt/myweb.log # 自定义日志文件myweb.log
2030-01-02 08:01:43 aaaaaaaaaaaaaaaaa
2030-01-02 08:34:23 bbbbbbbbbbbbbbbbbbbb
2030-01-02 09:23:12 ccccccccccccccccccccc
2030-01-02 10:56:13 ddddddddddddddddddddddddddd
2030-01-02 11:38:19 eeeeeeeeeeeeeeee
2030-01-02 12:02:28 ffffffffffffffff
[root@python day04]# vim timelog1.py
import time
# 时间戳或结构化时间能比较大小,将日志中行的时间信息转换为时间戳或结构化时间
f_time = '%Y-%m-%d %H:%M:%S'
t9 = time.strptime('2030-01-02 09:00:00', f_time) # 定义变量:9点的结构化时间
t12 = time.strptime('2030-01-02 12:00:00', f_time) # 定义变量:12点的结构化时间
with open('myweb.log', mode="r") as fr: # 读取日志文件myweb.log中的数据
for line in fr.readlines():
t = time.strptime(line[:19], f_time) # line[:19]提取时间信息,转换为结构化时间
if t9 <= t <= t12: # 这种比较方式会遍历每一行,可能执行大量无效操作,效率低
print(line, end='')
[root@python day04]# vim timelog2.py
import time
f_time = '%Y-%m-%d %H:%M:%S'
t9 = time.strptime('2030-01-02 09:00:00', f_time)
t12 = time.strptime('2030-01-02 12:00:00', f_time)
with open('myweb.log', mode="r") as fr:
for line in fr.readlines():
t = time.strptime(line[:19], '%Y-%m-%d %H:%M:%S')
if t > t12: # 当时间大于12点时,退出循环
break
if t >= t9: # 当时间大于9点时,打印对应行
print(line, end='')
keyword模块
- 列表
keyword.kwlist
包含Python的所有关键字。 - 函数
keyword.iskeyword("字符串")
判断字符串是否是Python中的关键字。
>>> import keyword
>>> keyword.kwlist # 查看python的关键字
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
>>> type(keyword.kwlist)
<class 'list'>
>>> 'pass' in keyword.kwlist # 判断是否是Python中的关键字
True
>>> keyword.iskeyword('pass') # 判断是否是Python中的关键字
True
builtins模块
- 在Python环境启动的时候就默认自动导入builtins模块。builtins内建模块包含函数**str()、int()、id()、type(),len()**等。
string字符串
占位符%s 、f字符串
- 直接调用任意类型变量的值的两种方式:
-
占位符%s:先挖坑再填坑。
"字符 %s 字符 %s %s" % (变量名1, 变量名2, 变量名3)
:返回一个字符串。第n个%s
的内容为str(变量名n)
-
f字符串:是 Python3.6 之后加入的标准库。边挖坑边填坑
f"字符 {变量名1} 字符 {变量名2}"
:返回一个字符串。
-
两种方式的变量可以传入任意类型的数据,如 整数、浮点数、列表、元组甚至字典,都会自动转成字符串类型。
-
# 直接调用任意变量值
>>> name, age, list01 = "benben", 25, [1, 2]
>>> str01 = "name: " + name + ", age: " + str(age) # 传统的字符串拼接,手动转换类型
>>> str01
'name: benben, age: 25'
>>> str02 = "name: %s, age: %s, %s" % (name, age, list01) # %s,先挖后填
>>> str02
'name: benben, age: 25, [1, 2]'
>>> str03 = f"name: {name}, age: {age}, {list01}" # f字符串,边挖边填
>>> str03
'name: benben, age: 25, [1, 2]'
string对象的函数
- string对象(不是string模块)有以下常用函数:
string对象.startswith('字符串')
:判断字符串是否是该string对象的开头。
string对象.endswith('字符串')
:判断字符串是否是该string对象的结尾。string对象.islower()
:判断该string对象的英文字母是否都是小写字母。
string对象.isupper()
:判断该string对象的英文字母是否都是大写字母。string对象.lower()
:将该string对象的英文字母转换为小写字母,返回一个新的string对象。
string对象.upper()
:将该string对象的英文字母转换为大写字母,返回一个新的string对象。string对象.lstrip()
:去除该string对象左边所有空白字符,返回一个新的string对象。
string对象.rstrip()
:去除该string对象右边所有空白字符,返回一个新的string对象。
string对象.strip()
:去除该string对象两边所有空白字符,返回一个新的string对象。- 空白字符:空格、换行符\n、制表符\t
string对象.split('分割符')
:以指定的分割符,分割该string对象,返回一个新的字符串列表。
string对象.split()
:以空格,分割该string对象,返回一个新的字符串列表。'拼接符'.join(字符串列表)
:以指定的拼接符,拼接该字符串列表的元素,返回一个新的string对象。
>>> s1 = "hello world"
>>> s1.startswith('abc') # startswith()判断字符串开头
False
>>> s1.startswith('he')
True
>>> s1.endswith('rld') # endswith()判断字符串结尾
True
>>> s2 = 'HELLO WORLD'
>>> s2.islower() # islower()判断字符串的英文字母是否都是小写字母
False
>>> s2.isupper() # isupper()判断字符串的英文字母是否都是大写字母
True
>>> s1.islower()
True
>>> s6 = 'hello 世界'
>>> s6.islower()
True
>>> s6.isupper()
False
>>> s7 = 'HELLO 世界@12.。'
>>> s7.islower()
False
>>> s7.isupper()
True
>>> s9 = 'Hello 世界@12.。'
>>> s9.lower() # lower()将字符串中的英文字母全部改为小写
'hello 世界@12.。'
>>> s9.upper() # upper()将字符串中的英文字母全部改为小写
'HELLO 世界@12.。'
>>> s9.endswith('。')
True
>>> s3 = ' hello world \t \n' # 空白字符包括空格、换行符\n、制表符\t
>>> print('l' + s3 + 'r')
l hello world
r
>>> print('l' + s3.lstrip() + 'r') # lstrip()去除字符串左边空格
lhello world
r
>>> print('l' + s3.rstrip() + 'r') # rstrip()去除字符串右边空格
l hello worldr
>>> print('l' + s3.strip() + 'r') # strip()去除字符串两边空格
lhello worldr
>>> s3
' hello world \t \n'
>>> s4 = 'hello world.tar.gz'
>>> s4.split() # split()分割字符串,返回列表。默认分割符为空格
['hello', 'world.tar.gz']
>>> s4.split('.') # 指定分割符为`.`
['hello world', 'tar', 'gz']
>>> s4.split('l') # 指定分割符为`l`
['he', '', 'o wor', 'd.tar.gz']
>>> s4
'hello world.tar.gz'
>>> alist = ['Hello', 'World', '!']
>>> '_'.join(alist) # join()拼接字符串列表的元素,返回string对象。必须指定拼接符。指定拼接符为`_`
'Hello_World_!'
>>> '.'.join(alist) # 指定拼接符为`.`
'Hello.World.!'
>>> ' '.join(alist) # 指定拼接符为空格
'Hello World !'
>>> ''.join(alist) # 指定拼接符为空
'HelloWorld!'
>>> type(''.join(alist))
<class 'str'>
>>> alist
['Hello', 'World', '!']
容器数据类型
- Python中的容器是指能存储多个元素的数据类型。包括列表list、元组tuple、集合set、字典dictionary
列表 list []
-
列表使用 [] 定义:
列表名 = [元素1, 元素2, 元素n]
- 列表中的元素可以是任意类型的对象,不同元素的类型可以是不同的。
-
列表是有序、可变的数据类型。
-
列表支持索引。切片和拼接会输出一个新列表,不改变原列表。
-
列表元素的个数、类型、值都可变。
-
列表按存储模型来分,属于容器类型;按更新模型来分,属于可变型;按访问模型来分,属于序列类型。
-
作用 | 相关函数 | 说明 |
---|---|---|
统计 | len(列表) | 列表长度(元素个数) |
列表.count(元素) | 元素在列表中出现的次数 | |
增加 | 列表.insert(索引, 元素) | 在指定索引的位置插入元素 |
列表.append(元素) | 在末尾追加该元素 | |
列表.extend(列表2) | 将列表2的元素分别追加到列表 | |
修改 | 列表[索引] = 新元素 | 修改指定索引的元素 |
删除 | 列表.remove(元素) | 删除第一个出现的指定元素 |
列表.pop(索引) | 抛出指定索引的元素,省略索引默认为-1。 抛出有返回值,删除无返回值 | |
del 元素 ,这里的元素是 列表[索引] | 删除该元素 | |
列表.clear | 清空列表,剩下空壳 [] | |
反转 | 列表.reverse() | 列表反转 |
排序 | 列表.sort() | 升序排序,列表中的元素类型需要统一 |
列表.sort(reverse=True) | 降序排序,列表中的元素类型需要统一 |
# 列表
>>> alist = [1, 'a', 2, 'c'] # 定义列表[]
>>> type(alist)
<class 'list'>
>>> alist.insert(2, 't') # insert插入元素
>>> alist
[1, 'a', 't', 2, 'c']
>>> alist.append('s') # append追加元素
>>> alist
[1, 'a', 't', 2, 'c', 's']
>>> alist.append([9, 'x']) # append将列表视为单个元素追加
>>> alist
[1, 'a', 't', 2, 'c', 's', [9, 'x']]
>>> alist.extend([9, 'x']) # extend将列表的元素视为个体追加
>>> alist
[1, 'a', 't', 2, 'c', 's', [9, 'x'], 9, 'x']
>>> alist[2] = 'x' # 修改元素,可以修改为任意类型
>>> alist
[1, 'a', 'x', 2, 'c', 's', [9, 'x'], 9, 'x']
>>> len(alist) # len列表长度
9
>>> alist.count('x') # count统计元素出现次数
2
>>> alist.count(9)
1
>>> alist.remove('x') # remove删除第一个匹配的元素
>>> alist
[1, 'a', 2, 'c', 's', [9, 'x'], 9, 'x']
>>> alist.remove('x')
>>> alist
[1, 'a', 2, 'c', 's', [9, 'x'], 9]
>>> alist.pop(-2) # pop抛出元素,有输出信息
[9, 'x']
>>> alist
[1, 'a', 2, 'c', 's', 9]
>>> alist.pop() # pop省略索引则默认为-1
9
>>> alist
[1, 'a', 2, 'c', 's']
>>> alist.clear() # clear清空列表,剩下空壳[]
>>> alist
[]
>>> blist = [11.3, 15, 16.4, 9.5, 5.90, 15]
>>> blist.reverse() # reverse反转列表元素
>>> blist
[15, 5.9, 9.5, 16.4, 15, 11.3]
>>> blist.sort() # sort列表元素升序
>>> blist
[5.9, 9.5, 11.3, 15, 15, 16.4]
>>> blist.sort(reverse=True) # sort函数的参数reverse=True则列表元素降序
>>> blist
[16.4, 15, 15, 11.3, 9.5, 5.9]
>>> clist = ['ahaha', 'cxixi', 'eip', 'bdc'] # 排序时列表元素的类型要统一
>>> clist.sort()
>>> clist
['ahaha', 'bdc', 'cxixi', 'eip']
>>> clist.sort(reverse=True)
>>> clist
['eip', 'cxixi', 'bdc', 'ahaha']
>>> dlist = [[1,2], [9,3], [2,4]] # 排序时列表元素的类型要统一
>>> dlist.sort()
>>> dlist
[[1, 2], [2, 4], [9, 3]]
>>> dlist.sort(reverse=True)
>>> dlist
[[9, 3], [2, 4], [1, 2]]
>>> elist = [['ahaha', 'hh'], ['cxixi', 20], ['bdc']] # 元素均是列表且元素列表的第一个元素类型相同,依次排序
>>> elist.sort()
>>> elist
[['ahaha', 'hh'], ['bdc'], ['cxixi', 20]]
# 切片和拼接会输出一个新列表,不改变原列表
>>> elist[-2:] # 切片
[['bdc'], ['cxixi', 20]]
>>> elist
[['ahaha', 'hh'], ['bdc'], ['cxixi', 20]]
>>> dlist + elist # 拼接
[[9, 3], [2, 4], [1, 2], ['ahaha', 'hh'], ['bdc'], ['cxixi', 20]]
>>> elist
[['ahaha', 'hh'], ['bdc'], ['cxixi', 20]]
随机加减法
# 练习:随机1~100以内加减法出题
1. 随机生成两个100以内的正数
2. 随机选择加减法运算,注意用大数减小数
3. 用户输入答案,返回结果
4. 一直出题,增加退出操作
import random
def exam():
nums = [random.randint(1,100) for i in range(2)] # 生成两个随机数的列表
nums.sort(reverse=True) # 列表降序排列
ope = random.choice('+-') # 随机运算符
# ope = random.choice(['+', '-'])
if ope == '+':
res = nums[0] + nums[1]
else:
res = nums[0] - nums[1]
guess = input('请输入 %s %s %s 的结果: ' % (nums[0], ope, nums[1])) # 占位符%s
if int(guess) == res:
print('回答正确')
else:
print(f'{nums[0]} {ope} {nums[1]} 的正确结果为 {res}') # f字符串
def show_menu():
while 1:
exam()
qu = input('退出请输入q/Q')
if qu == '':
continue
elif qu in 'qQ': # 注意`'' in '字符串'`为True,因此要提前排除
break
if __name__ == '__main__':
show_menu()
元组 tuple ()
-
元组使用
()
定义:元组名 = (元素1, 元素2, 元素n)
- 特殊的,单元素元组的定义:
元组名 = (元素,)
,(元素)
为元素本身的数据类型。 - 元组中的元素可以是任意类型的对象,不同元素的类型可以是不同的。
- 特殊的,单元素元组的定义:
-
元组是有序、不可变的数据类型。元组是不可变的列表。一般用于存储一些在程序中不应该被修改的一系列值。
- 元组支持索引,大部分列表操作都可以在元组中使用。
- 由于元组不可变的特性,所有没有增改删操作。
# 元组
>>> atuple = (1, 'a', ['df', 435], 'a', [1, 2])
>>> type(atuple)
<class 'tuple'>
# 大部分列表操作都可以在元组中使用
>>> len(atuple)
5
>>> atuple.count('a')
2
>>> atuple.count(1)
1
>>> 'a' in atuple
True
>>> 'a' not in atuple
False
>>> atuple[0] # 索引返回单个元素
1
>>> atuple[-1]
[1, 2]
>>> atuple[-3:] # 切片返回一个新的元组
(['df', 435], 'a', [1, 2])
>>> atuple
(1, 'a', ['df', 435], 'a', [1, 2])
>>> btuple = ('b', 9)
>>> atuple + btuple # 拼接返回一个新的元组
(1, 'a', ['df', 435], 'a', [1, 2], 'b', 9)
>>> atuple
(1, 'a', ['df', 435], 'a', [1, 2])
>>> del atuple[-1] # 元组是不可变的,不能增改删
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object doesn't support item deletion
# 特殊的,单元素元组:元组名 = (元素,)
>>> ctuple = (10);dtuple = ('h')
>>> type(ctuple);type(dtuple) # 单元素没加`,`则创建的非元组
<class 'int'>
<class 'str'>
>>> etuple = (10,) # 单元素元组正确的定义方式
>>> type(etuple)
<class 'tuple'>
>>> etuple
(10,)
字典 dict {键:值}
-
字典使用 {} 定义:
字典名 = {键1: 值1, 键2: 值2, 键n: 值1}
- 键是唯一不可重复的,键必须是可哈希的(不可变类型):字符串、数字(整数、浮点)、元组。
- 值是可重复的,能使用任意数据类型。
-
字典是无序、可变的数据类型。通常用于存储 描述一个物体的相关信息。
- 字典不支持索引。
作用 | 相关函数 | 说明 |
---|---|---|
统计 | len(字典) | 键值对数量 |
查询 | 字典[键] | 键存在则返回值,否则报错KeyError |
字典.get(键[, 错误信息]) | 键存在则返回值,否则返回错误信息,错误信息省略默认为None | |
字典.keys() | 返回一个列表,包含所有的键 | |
字典.values() | 返回一个列表,包含所有的值 | |
字典.items() | 返回一个列表,包含所有的键值对,每个键值对为一个元组 | |
增加/修改 | 字典[键] = 值 | 键存在则修改值,不存在则添加键值对 |
字典1.update(字典2) | 将字典2添加到字典1中,键存在则修改值,不存在则添加键值对 | |
删除 | 字典.pop(键) | 抛出指定键的键值对 |
del 字典[键] | 删除指定键的键值对 | |
字典.clear() | 清空字典,剩下空壳 {} |
# 字典
>>> info = {'age': 12, 'status': True, 'name': 'nfx'}
>>> type(info)
<class 'dict'>
>>> len(info) # len(字典),键值对数量
3
>>> info['name'] # 字典[键]
'nfx'
>>> info['score'] # 字典[键],键不存在则报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'score']
>>> info.get('name') # 字典.get(键, 错误信息),错误信息省略默认为None
'nfx'
>>> info.get('score')
>>> type(info.get('score'))
<class 'NoneType'>
>>> info.get('score', '没有成绩') # 字典.get(键, 错误信息)
'没有成绩'
>>> info.keys() # keys(),所有键
dict_keys(['age', 'status', 'name'])
>>> info.values() # values(),所有值
dict_values([12, True, 'nfx'])
>>> info.items() # items(),所有键值对
dict_items([('age', 12), ('status', True), ('name', 'nfx')])
>>> for i in info.keys(): # 遍历键
... print(i, info[i])
...
age 12
status True
name nfx
>>> for i in info: # 遍历键的简写
... print(i, info[i])
...
age 12
status True
name nfx
>>> for i in info.items():
... print(i[0], i[1], type(i))
...
age 12 <class 'tuple'>
status True <class 'tuple'>
name nfx <class 'tuple'>
>>> for i in info.items():
... print(f'{i[0]} {i[1]}', type(f'{i[0]} {i[1]}'))
...
age 12 <class 'str'>
status True <class 'str'>
name nfx <class 'str'>
>>> info
{'age': 12, 'status': True, 'name': 'nfx'}
>>> info['name'] = 'haha' # 键存在则修改值
>>> info
{'age': 12, 'status': True, 'name': 'haha'}
>>> info['email'] = '100@100.com' # 键不存在则添加键值对
>>> info
{'age': 12, 'status': True, 'name': 'haha', 'email': '100@100.com'}
>>> info2 = {'name': 'xixi', 'sex': 'male'}
>>> info.update(info2) # 字典1.update(字典2),将字典2添加到字典1中,键存在则修改值,不存在则添加键值对
>>> info
{'age': 12, 'status': True, 'name': 'xixi', 'email': '100@100.com', 'sex': 'male'}
>>> info.pop('email') # 字典.pop(键),抛出指定键的键值对
'100@100.com'
>>> info
{'age': 12, 'status': True, 'name': 'xixi', 'sex': 'male'}
>>> del info['sex'] # del 字典[键],删除指定键的键值对
>>> info
{'age': 12, 'status': True, 'name': 'xixi'}
>>> info.clear() # 字典.clear(),清空字典,剩下空壳 `{}`
>>> info
{}
用户注册登录
# 练习:模拟用户登录信息系统
1. 支持新用户注册(添加),新用户名和密码注册到字典中
2. 支持老用户登陆(查询),用户名和密码正确提示登陆成功
3. 主程序通过循环询问,进行何种操作,根据用户的选择,执行注册或是登陆操作
userdb = {} # 定义一个字典,用于存储用户名和密码
def register():
username = input('用户名: ')
if username == '':
print('您必须输入用户名')
elif username not in userdb:
password = input('密码: ')
userdb[username] = password
else:
print(f'用户名{username}已存在')
def login():
username = input('用户名: ')
password = input('密码: ')
# 方案1:if (username not in userdb) or (userdb[username] != password):
# 方案2
if (username, password) in userdb.items(): :
print('用户名或密码错误,登录失败')
else:
print('登录成功')
def show_menu():
prompt = """(0) 注册
(1)登陆
(2)退出
请做出选择(0/1/2): """
while 1:
choice = input(prompt)
if choice not in ['0', '1', '2']:
print('无效的输入,请重试。')
continue
if choice == '0':
register()
elif choice == '1':
login()
else:
print('Bye-bye')
break
if __name__ == '__main__':
show_menu()
集合 set {} 去重
-
集合使用
{}
定义:集合名 = {元素1, 元素2, 元素n}
-
集合内的元素不可重复、元素必须是可哈希的(不可变),因此集合不能修改。
-
集合内的元素
True
和1
通用,False
和0
通用。谁先留谁。
-
-
集合是无序、可变的数据类型。因此集合不支持索引,不能查询,不是用来存储数据的。
- 集合可以使用
in
、not in
、len(集合)
集合.add(元素1, 元素2, 元素n)
:集合添加元素。集合.remove(元素)
:集合删除单个元素。
- 集合可以使用
-
集合主要用于集合运算(交集、并集、差集)、列表去重。
- 交集(返回一个新集合):
集合1 & 集合2
或集合1.intersection(集合2)
- 并集(返回一个新集合):
集合1 | 集合2
或集合1.union(集合2)
- 差集(返回一个新集合):
集合1 - 集合2
或集合1.difference(集合2)
- 列表转集合(返回一个新集合):
set(列表)
集合转列表(返回一个新列表):list(集合)
- 交集(返回一个新集合):
>>> aset = {'a', 1, True, False, (9), ('x', 3), "world", (11, 22, 33)}
>>> aset
{False, 1, 'a', (11, 22, 33), 'world', 9, ('x', 3)} # 自动去重,True为1,False为0,谁先留谁
>>> bset = {True, 1}
>>> bset
{True}
>>> type(aset)
<class 'set'>
>>> len(aset)
7
>>> 'x' in aset
False
>>> 'a' in aset
True
>>> bset.add((78, ('a', 4)), 45.26) # add添加元素。集合的元素可以是数字、字符串、元组
>>> bset
{True, (78, ('a', 4)), 45.26}
>>> bset.add((78, ['a', 4])) # 特殊的,集合中的元组也不能使用可变数据作为元素
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> bset.remove(1) # remove删除单个元素。True为1,False为0
>>> bset
{(78, ('a', 4)), 45.26}
>>> bset.add(1)
>>> bset
{1, (78, ('a', 4)), 45.26}
>>> bset.remove(True)
>>> bset
{(78, ('a', 4)), 45.26}
>>> xset = xset = {"刘能", "赵四", "⽪⻓⼭"}
>>> yset = {"刘科⻓", "冯乡⻓", "⽪⻓⼭"}
# 交集
>>> xset & yset
{'⽪⻓⼭'}
>>> xset.intersection(yset)
{'⽪⻓⼭'}
# 并集
>>> xset | yset
{'刘能', '刘科⻓', '⽪⻓⼭', '冯乡⻓', '赵四'}
>>> xset.union(yset)
{'刘能', '刘科⻓', '⽪⻓⼭', '冯乡⻓', '赵四'}
# 差集
>>> xset - yset
{'刘能', '赵四'}
>>> xset.difference(yset)
{'刘能', '赵四'}
>>> yset - xset
{'冯乡⻓', '刘科⻓'}
>>> yset.difference(xset)
{'冯乡⻓', '刘科⻓'}
# 列表去重,得到新列表
>>> list1 = [11, 22, 33, 11, 3, 99, 22]
>>> set(list1)
{33, 3, 99, 11, 22}
>>> list(set(list1))
[33, 3, 99, 11, 22]
>>> list1
[11, 22, 33, 11, 3, 99, 22]
比较文件内容
# 练习:比较文件内容
1. 有两个文件:a.log 和 b.log
2. 两个文件中有大量重复内容
3. 取出只有在 a.log 中存在的行
[root@python day05]# cat a.log # 空格也占字符,有一行重复,9行不重复
sdfasdg
123456
21148
21345
123
123456
123456
aaaa
bbbb
4549
[root@python day05]# cat b.log # 7行不重复
sdfasdg
21345
123
aaaa
dddd
hhh
852
[root@python day05]# cat setdiff.py
fname1 = 'a.log'
fname2 = 'b.log'
# 读取文件内容,利用集合无序去重的特性,将所有行定义为一个集合,一行为一个元素
with open(fname1, mode="r") as fobj1:
aset = set(fobj1.readlines())
with open(fname2, mode="r") as fobj2:
bset = set(fobj2.readlines())
print('a.log:', aset)
print('b.log:', bset)
cset = aset - bset # 集合是无序的
print('只存在a.log的行:')
for line in list(cset): # 集合不可查,转化为列表
print(line, end='')
[root@python day05]# python3 setdiff.py
a.log: {'123456\n', ' 123456\n', 'aaaa\n', '21345\n', '123\n', 'bbbb\n', '4549\n', '21148\n', 'sdfasdg\n'}
b.log: {'dddd\n', 'aaaa\n', '21345\n', 'hhh\n', '123\n', '852\n', 'sdfasdg\n'}
只存在a.log的行:
123456
123456
bbbb
4549
21148
容器数据类型的比较
容器数据类型 | 列表list | 元组tuple | 字典dict | 集合set |
---|---|---|---|---|
定义方式 | [元素] | (元素,) | {键:值} | {元素} |
顺序与变化 | 有序、可变,可改 | 有序、不可变,不可改 | 无序、可变,可改 | 无序、可变,不可改 |
查增改删操作 | 查增改删 | 查 | 查增改删 | 增、删 |
长度 | 元素个数 | 元素个数 | 键值对数量 | 元素个数(自动去重) |
作用 | 存储可变数据 | 存储不可变列表 | 存储对象的描述信息 | 集合运算、列表去重 |
与系统交互的模块
shutil模块
shutil
模块(shell utility)是对os
模块的补充,主要针对文件的 复制、删除、移动、压缩和解压 操作。
作用 | shutil模块相关函数 | 说明 |
---|---|---|
复制文件内容和权限,不复制属性 | shutil.copy('源文件路径', '目标文件路径') | 可以覆盖 |
复制文件内容,不复制属性和权限 | shutil.copyfile('源文件路径', '目标文件路径') | 可以覆盖 |
复制文件内容,不复制属性和权限 | shutil.copyfileobj(源文件对象, 目标文件对象) | 文件对象关闭后才复制成功,可以覆盖 |
复制目录,不复制目录的属性 | shutil.copytree('源目录路径', '目标目录路径') | 目录保持权限, 目录内容保持属性和权限,不能覆盖 |
复制数据的权限,不复制内容和属性 | shutil.copymode('源数据路径', '目标数据路径') | 把文件或目录的权限复制给文件或目录 |
移动数据 | shutil.move('源数据路径', '目标路径') | 用法同move命令 |
修改数据的属性 | shutil.chown('数据路径', user='属主', group='属组') | |
删除目录 | shutil.rmtree('目录路径') | 相当于 rm -rf 目录 |
删除文件 | os.remove('文件路径') | 注意是os模块 |
// shutil 模块
[root@python ~]# cp /etc/{passwd,hosts} /mnt
[root@python ~]# chmod 777 /mnt/hosts
[root@python ~]# chown sshd:sshd /mnt/hosts
[root@python ~]# ll /mnt/hosts /mnt/passwd
-rwxrwxrwx 1 sshd sshd 158 Oct 13 14:15 /mnt/hosts
-rw-r--r-- 1 root root 1032 Oct 13 14:15 /mnt/passwd
[root@python ~]# chown ftp:ftp /opt
[root@python ~]# ll -d /opt/
drwxrwxrwx. 4 ftp ftp 32 Oct 13 08:52 /opt/
// 文件的复制
>>> import shutil
>>> shutil.copy('/mnt/hosts','/mnt/copy1') # copy复制文件内容和权限,不复制属性
'/mnt/copy1'
[root@python ~]# ll /mnt/copy1
-rwxrwxrwx 1 root root 158 Oct 13 14:18 /mnt/copy1
>>> shutil.copy('/mnt/passwd','/mnt/copy1') # copy覆盖
'/mnt/copy1'
[root@python ~]# ll /mnt/copy1
-rw-r--r-- 1 root root 1032 Oct 13 14:18 /mnt/copy1
>>> shutil.copyfile('/mnt/hosts','/mnt/copyfile1') # copyfile复制文件内容,不复制属性和权限
'/mnt/copyfile1'
[root@python ~]# ll /mnt/copyfile1
-rw-r--r-- 1 root root 158 Oct 13 14:19 /mnt/copyfile1
>>> shutil.copyfile('/mnt/passwd','/mnt/copyfile1') # copyfile覆盖
'/mnt/copyfile1'
[root@python ~]# ll /mnt/copyfile1
-rw-r--r-- 1 root root 1032 Oct 13 14:21 /mnt/copyfile1
>>> fr = open('/mnt/hosts',mode='r')
>>> fw = open('/mnt/copyfileobj1',mode='w')
>>> shutil.copyfileobj(fr,fw) # copyfileobj复制文件内容,文件对象关闭后才复制成功,不复制属性和权限
[root@python ~]# ll /mnt/copyfileobj1
-rw-r--r-- 1 root root 0 Oct 13 14:31 /mnt/copyfileobj1
>>> fr.close()
>>> fw.close()
[root@python ~]# ll /mnt/copyfileobj1 # 文件对象关闭后才复制成功
-rw-r--r-- 1 root root 158 Oct 13 14:32 /mnt/copyfileobj1
>>> fr = open('/mnt/passwd',mode='r')
>>> fw = open('/mnt/copyfileobj1',mode='w')
>>> shutil.copyfileobj(fr,fw) # copyfileobj覆盖
>>> fr.close()
>>> fw.close()
[root@python ~]# ll /mnt/copyfileobj1
-rw-r--r-- 1 root root 1032 Oct 13 14:34 /mnt/copyfileobj1
// 目录的复制
>>> shutil.copytree('/opt','/mnt/copytree1') # copytree递推复制目录,目录保持权限,目录内容保持属性和权限
'/mnt/copytree1'
[root@python ~]# ll -d /mnt/copytree1/
drwxrwxrwx. 4 root root 32 Oct 13 08:52 /mnt/copytree1/
>>> shutil.copytree('/tmp','/mnt/copytree1') # copytree不能覆盖,必须指定复制后的目录名,目标目录必须不存在
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.6/shutil.py", line 321, in copytree
os.makedirs(dst)
File "/usr/lib64/python3.6/os.py", line 220, in makedirs
mkdir(name, mode)
FileExistsError: [Errno 17] File exists: '/mnt/copytree1'
// 权限的复制
[root@python ~]# ll /mnt/hosts /mnt/passwd
-rwxrwxrwx 1 sshd sshd 158 Oct 13 14:15 /mnt/hosts
-rw-r--r-- 1 root root 1032 Oct 13 14:15 /mnt/passwd
[root@python ~]# ll /mnt/copyfile1
-rw-r--r-- 1 root root 1032 Oct 13 14:21 /mnt/copyfile1
>>> shutil.copymode('/mnt/hosts','/mnt/copyfile1') # copymode复制文件权限给文件,不复制内容和属性
[root@python ~]# ll /mnt/copyfile1
-rwxrwxrwx 1 root root 1032 Oct 13 14:21 /mnt/copyfile1
[root@python ~]# ll -d /mnt/copytree1/
drwxrwxrwx. 4 root root 32 Oct 13 08:52 /mnt/copytree1/
>>> shutil.copymode('/mnt/passwd','/mnt/copytree1') # copymode复制文件权限给目录
[root@python ~]# ll -d /mnt/copytree1/
drw-r--r--. 4 root root 32 Oct 13 08:52 /mnt/copytree1/
>>> shutil.copymode('/mnt/copytree1','/mnt/copyfile1') # copymode复制目录权限给文件
[root@python ~]# ll /mnt/copyfile1
-rw-r--r-- 1 root root 1032 Oct 13 14:21 /mnt/copyfile1
// 移动
>>> shutil.move('/mnt/hosts','/mnt/move1') # move移动文件或目录,使用方式同move命令
'/mnt/move1'
[root@python ~]# ll /mnt/move1
-rwxrwxrwx 1 sshd sshd 158 Oct 13 14:15 /mnt/move1
[root@python ~]# ll /mnt/hosts
ls: cannot access '/mnt/hosts': No such file or directory
>>> shutil.move('/mnt/copytree1','/mnt/move2')
'/mnt/move2'
[root@python ~]# ll -d /mnt/move2
drw-r--r--. 4 root root 32 Oct 13 08:52 /mnt/move2
[root@python ~]# ll -d /mnt/copytree1
ls: cannot access '/mnt/copytree1': No such file or directory
// 修改属性
[root@python ~]# ll /mnt/passwd
-rw-r--r-- 1 root root 1032 Oct 13 14:15 /mnt/passwd
>>> shutil.chown('/mnt/passwd',user='ftp',group='sshd') # chown修改文件或目录属性,属主属组必须是存在的
[root@python ~]# ll /mnt/passwd
-rw-r--r-- 1 ftp sshd 1032 Oct 13 14:15 /mnt/passwd
>>> shutil.chown('/mnt/passwd',group='ftp',user='sshd')
[root@python ~]# ll /mnt/passwd
-rw-r--r-- 1 sshd ftp 1032 Oct 13 14:15 /mnt/passwd
[root@python ~]# ll -d /mnt/move2
drw-r--r--. 4 root root 32 Oct 13 08:52 /mnt/move2
>>> shutil.chown('/mnt/move2',group='ftp',user='sshd')
[root@python ~]# ll -d /mnt/move2
drw-r--r--. 4 sshd ftp 32 Oct 13 08:52 /mnt/move2
// 删除目录
>>> shutil.rmtree('/mnt/move2') # rmtree删除目录
[root@python ~]# ll /mnt/move2
ls: cannot access '/mnt/move2': No such file or directory
os模块
- python对文件系统的操作大多通过 os模块实现。有些方法 os模块没有提供,可以使用 shutil模块作为补充。
作用 | os模块相关函数 | 说明 |
---|---|---|
查看当前目录,pwd | os.getcwd() | current working directory |
查看目录内容,ls -A | os.listdir('目录路径') | os.listdir() ,查看当前目录内容 |
创建单级目录,mkdir | os.mkdir('路径') | 需存在父目录 |
创建多级目录,mkdir -p | os.makedirs('路径') | |
进入目录,cd | os.chdir('路径') | |
删除空目录 | os.rmdir('空目录路径') | 删除目录使用shutil模块的rmtree函数 |
删除文件 | os.remove('文件路径') | |
判断字符串路径指向的数据是否是目录 | os.path.isdir('字符串') | 字符串路径指向的数据不存在则False |
判断字符串路径指向的数据是否是文件 | os.parh.isfile('字符串') | 字符串路径指向的数据不存在则False |
判断字符串路径本身是否是链接文件 | os.path.islink('字符串') | 链接指向的数据不存在也没关系,链接存在则True |
判断字符串路径是否存在 | os.path.exists('字符串') | |
判断字符串路径是否是绝对路径 | os.path.isabs('字符串') | 路径不存在也没关系,路径为绝对路径则True |
截取路径最后一个/ 右边的路径 | os.path.basename('字符串') | |
截取路径最后一个/ 左边的路径 | os.path.dirname('字符串') | |
以路径最后一个/ 分割路径,返回一个元组 | os.path.split('字符串') | 去除最后一个/ |
拼接最后一个以/ 开始的字符串和它之后的所有字符串 | os.path.join('字符串1', '字符串2', '字符串n') | 没有以/ 开始的字符串则拼接所有字符串,拼接符为/ |
# os模块的常用方法
>>> import os
# 查看
>>> os.getcwd() # getcwd,查看所处目录,相当于`pwd`
>>> os.listdir() # listdir,查看目录内容,省略为当前目录,相当于`ls -A`
[]
>>> os.listdir('/mnt')
['passwd', 'copy1', 'copyfile1', 'copyfileobj1', 'move1']
# 创建
>>> os.mkdir('/opt/day06/dir1') # mkdir,创建单级目录,必须存在父目录,相当于`mkdir`
>>> os.mkdir('/opt/day06/dir2/abc')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '/opt/day06/dir2/abc' # mkdir创建多级目录报错
>>> os.makedirs('/opt/day06/dir2/abc') # makedirs,创建多级目录,相当于`mkdir -p`
# 切换目录
>>> os.chdir('/mnt') # chdir,进入目录,相当于`cd`
>>> os.getcwd()
'/mnt'
# 删除
>>> os.remove('copyfile1')
>>> os.listdir()
['passwd', 'copy1', 'copyfileobj1', 'move1']
>>> os.rmdir('/opt/day06/dir2') # rmdir,删除空目录。直接删除目录使用shutil模块的rmtree
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 39] Directory not empty: '/opt/day06/dir2' # rmdir删除非空目录报错
>>> os.rmdir('/opt/day06/dir2/abc')
>>> os.rmdir('/opt/day06/dir2')
# 准备数据:目录、文件、链接指向目录、链接指向文件、链接指向不存在的文件
[root@python ~]# mkdir /opt/day06/pathdir
[root@python ~]# touch /opt/day06/pathfile.txt
[root@python ~]# ln -s /opt/day06/pathdir /opt/day06/linkdir
[root@python ~]# ln -s /opt/day06/pathfile.txt /opt/day06/linkfile.txt
[root@python ~]# ln -s /opt/day06/pathwrong /opt/day06/linkwrong
[root@python ~]# ll /opt/day06
total 0
drwxr-xr-x 2 root root 6 Oct 13 16:02 dir1
lrwxrwxrwx 1 root root 19 Oct 13 16:47 linkdir -> /opt/day06/pathdir/
lrwxrwxrwx 1 root root 23 Oct 13 16:48 linkfile.txt -> /opt/day06/pathfile.txt
lrwxrwxrwx 1 root root 20 Oct 13 17:23 linkwrong -> /opt/day06/pathwrong
drwxr-xr-x 2 root root 6 Oct 13 16:46 pathdir
-rw-r--r-- 1 root root 0 Oct 13 16:46 pathfile.txt
# 判断
>>> os.path.isdir('/opt/day06/pathdir') # isdir,判断路径指向的数据是否是目录
True
>>> os.path.isdir('/opt/day06/linkdir') # 链接则判断指向的源数据
True
>>> os.path.isdir('opt/day06/pathwrong') # 路径不存在也不报错
False
>>> os.path.isfile('/opt/day06/pathfile.txt') # isfile,判断路径指向的数据是否是文件
True
>>> os.path.isfile('/opt/day06/linkfile.txt') # 链接则判断指向的源数据
True
>>> os.path.isfile('opt/day06/pathwrong') # 路径不存在也不报错
False
>>> os.path.islink('/opt/day06/linkfile.txt') # islink,判断路径本身是否是链接
True
>>> os.path.islink('/opt/day06/linkdir')
True
>>> os.path.islink('/opt/day06/linkwrong') # 链接指向的源数据不存在也没关系
True
>>> os.chdir('/etc')
>>> os.path.exists('passwd') # exists,判断路径是否存在
True
>>> os.path.isabs('passwd') # isabs,判断路径是否是绝对路径。路径不存在也没关系
False
>>> os.path.exists('/etc/pass')
False
>>> os.path.isabs('/etc/pass') # 路径不存在也没关系
True
# 截取
>>> os.path.basename('/opt/day06/pathwrong/') # basename,截取路径最后一个`/`右边的路径
''
>>> os.path.basename('/opt/day06/pathwrong')
'pathwrong'
>>> os.path.dirname('/opt/day06/pathwrong') # dirname,截取路径最后一个`/`左边的路径
'/opt/day06'
>>> os.path.dirname('/opt/day06/pathwrong/')
'/opt/day06/pathwrong'
>>> os.path.dirname('day06/pathwrong')
'day06'
# 分割
>>> os.path.split('/opt/day06/pathdir') # split,以路径最后一个`/`分割路径,返回一个元组
('/opt/day06', 'pathdir')
>>> os.path.split('/opt/day06/pathdir/')
('/opt/day06/pathdir', '')
>>> type(os.path.split('/opt/day06/pathdir/'))
<class 'tuple'>
# 拼接
>>> os.path.join('/abc/def','elf/ps') # join,拼接最后一个以`/`开始的字符串和它之后的所有字符串
'/abc/def/elf/ps'
>>> os.path.join('/abc/def/','elf/ps')
'/abc/def/elf/ps'
>>> os.path.join('/abc/def','/elf/ps')
'/elf/ps'
>>> os.path.join('/abc/def','elf/ps','jkl')
'/abc/def/elf/ps/jkl'
>>> os.path.join('/abc/def','/elf/ps','jkl')
'/elf/ps/jkl'
>>> os.path.join('abc/def','elf/ps','jkl')
'abc/def/elf/ps/jkl'
subprocess.run()
- subprocess 模块主要用于执行 系统命令。subprocess 模块允许产生新的进程,并获得它们的返回状态。通俗地说就是通过这个模块,你可以在 Python 的代码里执行操作系统级别的命令,比如 “ifconfig” 、“du -sh” 等等。
- subprocess模块只能在linux平台运行。
run函数的使用方式
- subprocess模块的run函数可以直接执行系统命令,执行完命令返回一个CompletedProcess 类型对象。
- 两种使用方式:
subprocess.run('命令', shell=True)
:启动识别shell命令。subprocess.run(['参数1', '参数2', '参数n'])
:一条命令的每个字符串都是列表中的一个元素。
- 特殊的,涉及环境变量只能使用第一种方式:
subprocess.run('命令', shell=True)
- 两种使用方式:
# subprocess.run函数的两种使用方式
>>> import subprocess
>>> subprocess.run('ls -ld /opt') # 报错
>>> subprocess.run('ls -ld /opt', shell=True) # 启用识别shell命令
drwxrwxrwx. 5 ftp ftp 45 Oct 13 15:27 /opt
CompletedProcess(args='ls -ld /opt', returncode=0)
>>> subprocess.run(['ls', '-l', '-d', '/opt']) # 命令的每个字符串都是列表的一个元素
drwxrwxrwx. 5 ftp ftp 45 Oct 13 15:27 /opt
CompletedProcess(args=['ls', '-l', '-d', '/opt'], returncode=0)
>>> subprocess.run(['ls', '-ld', '/opt'])
drwxrwxrwx. 5 ftp ftp 45 Oct 13 15:27 /opt
CompletedProcess(args=['ls', '-ld', '/opt'], returncode=0)
>>> subprocess.run('echo $HOME', shell=True) # 涉及环境变量只能使用第一种方式
/root
CompletedProcess(args='echo $HOME', returncode=0)
>>> subprocess.run('echo', '$HOME') # 报错
returncode返回码
- run函数会返回一个CompletedProcess 类型对象
CompletedProcess(args='命令', returncode=返回码)
,可以使用.returncode
来获取该返回码。
# subprocess.run()返回码
>>> import subprocess
>>> import os
>>> os.chdir('/etc')
>>> os.getcwd()
'/etc'
>>> subprocess.run('ls -l passwd', shell=True)
-rw-r--r--. 1 root root 1032 Nov 15 2022 passwd
CompletedProcess(args='ls -l passwd', returncode=0) # 执行命令成功,则returncode返回码为0
>>> subprocess.run('ll passwd', shell=True)
/bin/sh: ll: command not found
CompletedProcess(args='ll passwd', returncode=127)
>>> subprocess.run('ls -l pass', shell=True)
ls: cannot access 'pass': No such file or directory
CompletedProcess(args='ls -l pass', returncode=2)
>>> res = subprocess.run('ls -l passwd', shell=True)
-rw-r--r--. 1 root root 1032 Nov 15 2022 passwd
>>> type(res)
<class 'subprocess.CompletedProcess'>
>>> res.returncode
0
# 练习:ping命令
1. 编写 ping 函数,用于测试远程主机的联通性
2. ping 通显示:**x.x.x.x:up**
3. ping 不通显示:**x.x.x.x:down**
import subprocess
def ping(host):
result = subprocess.run('ping -c 2 %s &> /dev/null' % host, shell=True) # 使用占位符%s调用变量
# 使用f字符串调用变量 result = subprocess.run(f'ping -c 2 {host} &> /dev/null', shell=True)
if result.returncode == 0:
return '%s:up' % host # 使用占位符%s调用变量
# 使用f字符串调用变量 return f'{host}:up'
else:
return '%s:down' % host
if __name__ == '__main__':
print(ping('127.0.0.1'))
print(ping('www.baidu.com'))
创建用户
# 练习:创建用户并设置密码
1. 用户输入用户名
2. 如果用户名不存在则创建用户并设置一个8位的随机密码
3. 将用户名和随机密码写入文件/tmp/user.txt
import random,string,subprocess
def get_pwd(n=8):
sec = ""
for i in range(n):
sec += random.choice(string.digits + string.ascii_letters)
return sec
def useradd():
while 1:
username = input('请输入用户名:')
if username == '':
continue
else:
break
info = subprocess.run(f'id {username} &> /dev/null', shell=True)
if info.returncode == 0:
print('用户%s已存在' % username)
else:
pwd = get_pwd()
subprocess.run(f'useradd {username}', shell=True)
subprocess.run(f'echo {pwd} | passwd --stdin {username}', shell=True)
with open('/tmp/user.txt', mode='a') as fw:
fw.write(f'user: {username}\t pwd: {pwd}\n')
if __name__ == '__main__':
useradd()
异常 exception
- Python中异常是指,在运行Python脚本的过程中,发生错误而导致程序运行的提前终止。
- 抛出异常:在运行Python脚本的过程中发生错误,系统会提前终止程序运行,且发生错误的原因返回相应的traceback消息。
- 捕获异常:使用try语句捕获代码执行过程中发生的异常并进行对应的处理。
常见异常
-
常见异常:
NameError
:使用了一个未定义的变量或函数。TypeError
:操作或函数应用于不适当类型的对象。ValueError
:传递给函数的参数是正确类型但具有无效值的错误。IndexError
:使用序列中不存在的索引进行访问的错误。KeyError
:使用字典中不存在的键进行访问的错误。FileNotFoundError
:访问不存在的文件的错误。ImportError
:导入模块或者对象失败的错误AttributeError
:访问不存在的对象属性或方法的错误。SyntaxError
:语法错误。ZeroDivisionError
:除法或者求余运算中除数为零的错误。KeyboardInterrupt
:用户提前终止程序的执行的错误。Linux的Ctrl+C,Windows的Ctrl+BreakEOFError
:在尝试读取输入时遇到EOF输入结束的错误。Linux的Ctrl+D,Windows的Ctrl+Z。IOError
:输入或输出操作失败。Exception
:常规错误的基类。BaseException
:所有异常的基类,如果需要捕获所有的异常,可以使用该类。
-
Exception
和BaseException
的区别:Exception
是大多数常见异常类的基类。这意味着大部分由于程序错误或意外情况引起的异常都继承自Exception
类。例如,TypeError
、ValueError
、IOError
等都是Exception
类的子类。BaseException
是所有异常类的根基类,是Exception
类的父类。这意味着除了Exception
类,还有其他异常类直接或间接地继承自BaseException
。例如,SystemExit
、KeyboardInterrupt
等都是直接继承自BaseException
的异常类。
因此,
Exception
是大多数常见异常的基类,而BaseException
是所有异常的根基类。一般来说,在编写异常处理代码时,最好捕获Exception
类而不是BaseException
类,以防止捕获到不应该处理的异常,如SystemExit
或KeyboardInterrupt
。
# 查看预定义的索引异常
>>> import builtins
>>> exceptions = [name for name, obj in vars(builtins).items() if isinstance(obj, type) and issubclass(obj, BaseException)]
>>> print(exceptions)
['BaseException', 'Exception', 'TypeError', 'StopAsyncIteration', 'StopIteration', 'GeneratorExit', 'SystemExit', 'KeyboardInterrupt', 'ImportError', 'ModuleNotFoundError', 'OSError', 'EnvironmentError', 'IOError', 'EOFError', 'RuntimeError', 'RecursionError', 'NotImplementedError', 'NameError', 'UnboundLocalError', 'AttributeError', 'SyntaxError', 'IndentationError', 'TabError', 'LookupError', 'IndexError', 'KeyError', 'ValueError', 'UnicodeError', 'UnicodeEncodeError', 'UnicodeDecodeError', 'UnicodeTranslateError', 'AssertionError', 'ArithmeticError', 'FloatingPointError', 'OverflowError', 'ZeroDivisionError', 'SystemError', 'ReferenceError', 'BufferError', 'MemoryError', 'Warning', 'UserWarning', 'DeprecationWarning', 'PendingDeprecationWarning', 'SyntaxWarning', 'RuntimeWarning', 'FutureWarning', 'ImportWarning', 'UnicodeWarning', 'BytesWarning', 'ResourceWarning', 'ConnectionError', 'BlockingIOError', 'BrokenPipeError', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionRefusedError', 'ConnectionResetError', 'FileExistsError', 'FileNotFoundError', 'IsADirectoryError', 'NotADirectoryError', 'InterruptedError', 'PermissionError', 'ProcessLookupError', 'TimeoutError']
>>> a + 5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined # NameError,未定义的变量或函数
>>> 'hello'[5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range # IndexError,索引错误
>>> 8 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero # ZeroDivisionError,余数为0错误
>>> a = 10
>>> if a = 10:
File "<stdin>", line 1
if a = 10:
^
SyntaxError: invalid syntax # SyntaxError,语法错误
>>> n = input('number:' ) , 产生EOFError
number:Traceback (most recent call last): # 要求输入number时,Ctrl+D
File "<stdin>", line 1, in <module>
EOFError # EOFError,输入提前结束错误
>>> n = input('number: ')
number: Traceback (most recent call last): # 要求输入number时,Ctrl+C
File "<stdin>", line 1, in <module>
KeyboardInterrupt # KeyboardInterrupt,程序终止执行错误
捕获异常 try、except、else、finally
- 在程序执行时,可能会遇到不同类型的异常,并且需要针对不同类型的异常,做出不同的响应,这个时候,就需要根据错误类型捕获异常了。
- try语句会捕获代码执行过程中的异常。
- except子句指定具体的错误类型的响应方案。
- else子句是不发生异常时执行的代码。
- finally子句是无论异常是否发生,是否被捕获,都一定会执行的代码。如果打开文件后,因为发生异常导致文件没有关闭,可能会发生数据损坏,使用finally 可以保证文件总是能正常的关闭。
# 捕获异常的语法
try:
尝试执行的代码
except 错误类型1: # 针对具体的错误类型,可以使用`as 变量名`
针对错误类型1,对应的代码处理 # 响应方案
except (错误类型2, 错误类型3): # 相同处理方式的多种错误类型的写法
针对错误类型2 和 3,对应的代码处理
except Exception: # Exception基类,处理属于基类但没有使用except指出的异常
针对属于基类但没有使用except指出的异常,对应的代码处理
else:
不发生异常时执行的代码
finally:
无论异常是否发生,是否被捕获,都会执行的代码
# `as 变量名`
try:
尝试执行的代码
except 错误类型 as 变量名: # 可以使用`as 变量名`来调用具体的错误类型
print('未知错误 %s' % 变量名)
# 捕获异常的示例
[root@python day06]# vim exception01.py
try:
n = int(input('number: '))
res = 100 / n
print(res)
except ValueError:
print('无效的输入')
except (KeyboardInterrupt, EOFError):
print('\nBye-bye')
except Exception:
print('未知错误')
[root@python day06]# python3 exception01.py
number: # 直接回车
无效的输入 # ValueError
[root@python day06]# python3 exception01.py
number: ^C # Ctrl+C
Bye-bye # KeyboardInterrupt
[root@python day06]# python3 exception01.py
number: # Ctrl+D
Bye-bye # EOFError
[root@python day06]# python3 exception01.py
number: 0
未知错误 # ZeroDivisionError属于Exception
# `as 变量名`的示例
[root@python day06]# vim exception02.py
try:
n = int(input('number: '))
res = 100 / n
print(res)
except ValueError as e:
print('无效的输入', e)
except (KeyboardInterrupt, EOFError) as e:
print('\nBye-bye', e)
except Exception as e:
print('未知错误', e)
[root@python day06]# python3 exception02.py
number: # 直接回车
无效的输入 invalid literal for int() with base 10: ''
[root@python day06]# python3 exception02.py
number: ^C # Ctrl+C
Bye-bye
[root@python day06]# python3 exception02.py
number: # Ctrl+D
Bye-bye
[root@python day06]# python3 exception02.py
number: 0
未知错误 division by zero
# else和finally
[root@python day06]# vim exception03.py
try:
n = int(input('number: '))
res = 100 / n
print(res)
except Exception as e:
print('未知错误', e)
else: # else,不发生异常时执行的代码
print('正常结束')
finally: # finally,一定执行的代码
print('finally')
[root@python day06]# python3 exception03.py
number: 0
未知错误 division by zero
finally
[root@python day06]# python3 exception03.py
number: 2
50.0
正常结束
finally
自定义异常 raise
- Python解释器会代码执行出错时自动抛出预定义的异常,除此之外,用户还可以自定义异常,让Python解释器根据用户需求主动抛出异常。
- 抛出自定义异常:
raise 异常类型('输出信息')
# 练习:要求用户输入8位以上密码
def input_password():
pwd = input("请输入密码:")
if len(pwd) >= 8:
return pwd
raise Exception("密码长度不够")
if __name__ == '__main__':
user_pwd = input_password()
print(user_pwd)
# 执行结果
请输入密码:asdf
Traceback (most recent call last):
File "/home/student/PycharmProjects/pythonProject2/test02/te.py", line 7, in <module>
user_pwd = input_password()
File "/home/student/PycharmProjects/pythonProject2/test02/te.py", line 5, in input_password
raise Exception("密码长度不够")
Exception: 密码长度不够
# 练习:要求输入一个18到60之间的年龄
def get_info(name, age):
age = int(age)
if not 18 <= age <= 60:
raise ValueError('无效的年龄(1 ~ 119)')
else:
print('%s is %s years old' % (name, age))
if __name__ == '__main__':
nam = input('请输入姓名:')
ag = input('请输入年龄:')
get_info(nam, ag)
# 执行结果
请输入姓名:ja
请输入年龄:0
Traceback (most recent call last):
File "/home/student/PycharmProjects/pythonProject2/test02/te.py", line 10, in <module>
get_info(nam, ag)
File "/home/student/PycharmProjects/pythonProject2/test02/te.py", line 4, in get_info
raise ValueError('无效的年龄(1 ~ 119)')
ValueError: 无效的年龄(1 ~ 119)
生成器 generator
-
在Python中,生成器是一种特殊的迭代器,可以按需生成序列中的元素。生成器使用了延迟计算的概念,只在需要生成元素时才会进行计算,从而节省了内存和运算时间。
- 生成器和列表的区别:
- 生成器实现了延迟计算,只在需要时才生成元素,因此生成器节省内存空间。而列表直接把所有元素存储在内存中。
- 生成器具有惰性求值的特性,只在需要时才进行计算,可以提高程序的效率。列表一旦创建,元素就会立即计算,并占用内存。
- 生成器适用于处理大型数据集或无限序列,可以逐步生成数据。列表适用于需要立即访问和修改元素的情况。
- 生成器是一次性的,每个生成器一旦迭代完毕,就不能再继续迭代。列表可以在任何时候访问其中的元素。
- 生成器和列表的区别:
-
获取生成器(按需生成)的两种方式:
- 生成器表达式,类似于列表推导,但是,生成器返回的是一个按需产生的对象。
- 生成器函数:使用常规的函数定义方式,但是,使用 yield语句返回结果而不是return语句。
-
生成器使用yield语句来定义一个或多个生成元素的规则。当生成器函数被调用时,它会返回一个生成器对象,而不是立即执行函数体中的代码。每次通过生成器对象迭代时,它会执行生成器函数的代码,直到遇到yield语句,然后返回yield后面的值。当再次迭代时,它会从上次离开的地方继续执行。
-
yield语句表示暂时挂起函数,下次继续执行之后的代码。一个yield语句返回一个结果。
-
return语句表示终止函数,是函数的结束,return语句之后的代码全部不执行。
-
如果在生成器函数内部,使用了多个 yield语句返回中间结果:
- 程序向生成器函数取值时,当生成器函数执行到第1个yield时,会暂停函数运行并返回第一个结果;
- 当主程序再次调用该函数时,函数会从上次暂停的位置继续运行,当遇到第2个yield,会再次暂停运行函数并返回第二个结果;
- 重复以上操作,一直到函数内部的yield全部执行完成为止。
-
- 获取生成器元素的方式:
生成器.__next()__
:每次获取一个剩余的元素。for i in 生成器: print(i)
:获取剩余所有元素。- 注意每个生成器只能遍历一次,之后再获取单个元素会抛出StopIteration异常。
生成器
# 生成器
# 获取生成器方式一:生成器表达式
# 列表推导式
>>> import random
>>> list01 = [random.randint(1,5) for i in range(5)]
>>> list01
[3, 3, 4, 1, 4]
>>> type(list01)
<class 'list'> # 列表类型
# 生成器表达式
>>> gen01 = (random.randint(1,5) for i in range(5))
>>> gen01
<generator object <genexpr> at 0x7f5f34dfaf10> # 生成器对象
>>> type(gen01)
<class 'generator'> # 生成器类型
# 获取生成器元素方式一:每次获取一个剩余的元素
>>> print('data:', gen01.__next__())
data: 1 # 剩余四个元素
>>> print('data:', gen01.__next__())
data: 5 # 剩余三个元素
# 获取生成器元素方式二:获取剩余所有元素
>>> for i in gen01: print('date:', i)
...
date: 3
date: 3
date: 5 # 没有剩余元素
# 生成器当中的元素只能获取一遍
>>> print('data:', gen01.__next__()) # 报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> for i in gen01: print('date:', i) # 不报错
...
# 获取生成器方式二:生成器函数
>>> def fun01():
... a = 1
... yield a # yield表示函数的暂停,暂时挂起,下次继续执行之后的代码
... b = 'hellp'
... c = [1, 2]
... yield c
... yield b
... d = ('xi', 3)
... yield d
...
>>> gen02 = fun01()
>>> gen02
<generator object fun01 at 0x7f5f34dfaeb8> # 生成器对象
>>> type(gen02)
<class 'generator'> # 生成器类型
>>> print('data:', gen02.__next__())
data: 1
>>> print('data:', gen02.__next__())
data: [1, 2]
>>> for i in gen02: print('data:', i)
...
data: hellp
data: ('xi', 3)
>>> print('data', gen02.__next__()) # 报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> for i in gen02: print('data:', i) # 不报错
...
# 生成器的主要优点在于延迟操作,需要的时候再使用,所以会节省空间
>>> sum([i for i in range(100000000)]) # 列表推导式
已杀死
[root@python day07]# # 系统杀死python进程
>>> sum((i for i in range(100000000))) # 生成器表达式
4999999950000000
列表推导式会先生成一个包含所有元素的列表,然后将该列表传递给sum()函数来计算总和。这意味着在计算总和之前,整个列表将存在于内存中
生成器表达式创建一个生成器对象,它是一个可迭代的序列。生成器在需要时逐个生成元素,每次只生成一个元素。因此,在计算的过程中,生成器只会在内存中保留当前生成的元素,而不是保存整个列表。这种方式更加节省内存,并且在处理大数据集时更加高效
读取文件生成器
# 练习:读取文件生成器
1. 使用函数实现生成器 yield
2. 函数接受一个文件路径作为参数,函数实现读取文件
3. 生成器函数每次读取文件的10行数据
# 思路:程序 = 数据结构(list) + 算法
1.按行读取文件,按行读取(while True+readline / readlines)
2.读一行给列表中添加一个元素(行数据)
3.判断此时列表的长度是否为10,是则通过yield将列表返回,清空列表
4.文件读取完毕,判断列表是否为空,若不为空将剩余数据返回
def gen_file(filename): # 使用yield的函数是一个生成器
line10 = []
with open(filename, mode='r') as fr:
for line in fr.readlines(): # 遍历列表的元素,文件对象.readlines()为一个列表,每个元素为一行数据
line10.append(line) # 列表追加元素
if len(line10) == 10: # 列表长度为10,也就是遍历了10个元素,即10行数据
yield line10 # 通过yield将列表返回
line10.clear() # 清空列表
if len(line10) != 0: # 兜底,返回剩余的少于10行的数据,保证文件读取的完整性
yield line10
if __name__ == '__main__':
gen = gen_file('/etc/passwd') # 调用函数,函数为一个生成器,gen类型为generator
for item in gen: # item是存储行数据的列表,类型为list
n = len(item)
for i in range(n):
print(item[i],end='')
print('========================')
其它模块
hashlib模块
- hashlib模块是Python中用于处理hash算法的模块。用来替换 MD5模块和 sha模块,并使他们的API一致。
- hashlib模块通过多个函数来支持多种hash算法:md5、sha1、sha224、sha256、sha384、sha512
- 例如:
hashlib.md5(b'字符串')
获得一个MD5对象,MD5对象.hexdigest()
获得十六进制的值
- 例如:
- hashlib模块通过多个函数来支持多种hash算法:md5、sha1、sha224、sha256、sha384、sha512
# hashlib.md5(),计算bytes类型数据的md5值
>>> import hashlib
>>> hashlib.md5('123456') # 报错,md5函数的实参必须是字节串
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Unicode-objects must be encoded before hashing
>>> hashlib.md5(b'123456') # 使用b'字符串'获得字节串,md5函数返回一个md5对象
<md5 HASH object @ 0x7f7c6e1ec800>
>>> m = hashlib.md5(b'123456')
>>> m.hexdigest() # hexdigest函数,以十六进制的方式,显示md5对象的值
'e10adc3949ba59abbe56e057f20f883e'
# 每次读取少量数据,最后计算出文件的md5值,适合于大文件数据
>>> m1 = hashlib.md5() # 返回一个空数据的md5值
>>> m1.update(b'12') # 计算字符串拼接'12'的md5值,'12'
>>> m1.update(b'34') # 计算字符串拼接'34'的md5值,'1234'
>>> m1.update(b'56') # 计算字符串拼接'56'的md5值,'123456'
>>> m1.hexdigest() # 与m的结果相同
'e10adc3949ba59abbe56e057f20f883e'
# 练习:计算大文件的md5值
[root@python ~]# vim hashlib01.py
import hashlib,sys
def check_md5(filename):
m = hashlib.md5()
with open(filename, mode='rb') as fr:
while 1:
data = fr.read(1024*4)
if len(data) == 0:
break
m.update(data) # 由于rb,所以data是字节串,加入是r,则需要b'data'
return m.hexdigest()
if __name__ == '__main__':
print(check_md5(sys.argv[1]))
[root@python ~]# chmod +x hashlib01.py
[root@python ~]# ./hashlib01.py /etc/hosts
54fb6627dbaa37721048e4549db3224d
tarfile模块
- tarfile模块允许创建、访问 tar 文件。同时支持 gzip、bzip2 格式。
tarfile.open('压缩包路径', mode='模式')
:创建一个tarfile的对象,打开该压缩包文件。
常用的mode | action |
---|---|
'r' or 'r:*' | 打开压缩包只读 |
'r:gz' 、'r:bz2' 、'r:xz' | 打开压缩包只读 |
'x' or 'x:' | 创建压缩包,已存在则异常FileExistsError |
'x:gz' 、'x:bz2' 、'x:xz' | 创建压缩包,已存在则异常FileExistsError |
'w' or 'w:' | 打开压缩包写入。文件不存在则自动创建,文件存在则无需指定压缩格式。 |
'w:gz' 、'w:bz2' 、'w:xz' | 打开压缩包写入。文件不存在则自动创建,文件存在则无需指定压缩格式。 |
- 打包:
tarfile.open('压缩包路径', mode='模式')
:创建一个tarfile的对象,打开该压缩包文件。文件不存在则自动创建,文件存在则无需指定压缩格式。tarfile对象.add('数据路径')
:向压缩包文件中压缩数据。tarfile对象.close()
:关闭压缩包文件。
- 解压:
tarfile.open('压缩包路径')
:创建一个tarfile的对象,打开该压缩包文件。tarfile对象.extract('文件路径', path='解压目录')
:提取压缩包文件中的该文件到该目录下,不指定解压目录则解压到当前目录下。tarfile对象.extractall(path='解压目录')
:提取压缩包文件中的所有文件到该目录下,不指定解压目录则解压到当前目录下。tarfile对象.close()
:关闭压缩包文件。
>>> import tarfile
# 打包
>>> tar01 = tarfile.open('/tmp/demo.tar.gz', mode='w:gz') # 以'w:gz'的格式,打开包文件,文件不存在则会自动创建
>>> type(tar01)
<class 'tarfile.TarFile'>
>>> tar01.add('/etc/hosts') # 向包文件中压缩文件/etc/hosts
>>> tar01.add('/etc/security') # 向包文件中压缩目录/etc/security
>>> tar01.close() # 关闭包文件
[root@python ~]# ll /tmp/demo.tar.gz
-rw-r--r-- 1 root root 9426 1月 5 19:54 /tmp/demo.tar.gz
# 提取单个文件
>>> tar03 = tarfile.open('/tmp/demo.tar.gz')
>>> tar03.extract('etc/hosts', '/tmp')
>>> tar03.close()
[root@python ~]# ll /tmp/etc/
总用量 4
-rw-r--r-- 1 root root 158 9月 10 2018 hosts
# 提取所有文件
>>> tar02 = tarfile.open('/tmp/demo.tar.gz') # 打开文件,文件已经存在,则不需要指定类型,python会自动选择
>>> tar02.extractall(path='/var/tmp') # 解压到/var/tmp目录下,不指定则解压到当前目录下
>>> tar02.close() # 关闭包文件
[root@python ~]# ll /var/tmp/etc/
总用量 8
-rw-r--r-- 1 root root 158 9月 10 2018 hosts
drwxr-xr-x 7 root root 4096 8月 7 23:38 security