# python

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(,)			# 省略步长默认为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

  • 文件的复制就是一读一写。普通文件的底层也是二进制文件,因此使用模式 rbwb 来复制二进制文件。
    • 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 的元素是字符串类型
# 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. 如果不指定位数,默认8import 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(年)0xxxx,比如 2021
tm_mon(月)11 - 12
tm_mday(日)21 - 31
tm_hour(时)30 - 23
tm_min(分)40 - 59
tm_sec(秒)50 - 59
tm_wday(周几的索引)60 - 6(0表示周一,6表示周日)
tm_yday(一年中的第几天)71 - 366
tm_isdst(是否是夏令时)80为否,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}

    • 集合内的元素不可重复、元素必须是可哈希的(不可变),因此集合不能修改。

    • 集合内的元素 True1 通用,False0 通用。谁先留谁。

  • 集合是无序、可变的数据类型。因此集合不支持索引,不能查询,不是用来存储数据的。

    • 集合可以使用innot inlen(集合)
    • 集合.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模块相关函数说明
查看当前目录,pwdos.getcwd()current working directory
查看目录内容,ls -Aos.listdir('目录路径')os.listdir(),查看当前目录内容
创建单级目录,mkdiros.mkdir('路径')需存在父目录
创建多级目录,mkdir -pos.makedirs('路径')
进入目录,cdos.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+Break
    • EOFError:在尝试读取输入时遇到EOF输入结束的错误。Linux的Ctrl+D,Windows的Ctrl+Z。
    • IOError:输入或输出操作失败。
    • Exception:常规错误的基类。
    • BaseException:所有异常的基类,如果需要捕获所有的异常,可以使用该类。
  • ExceptionBaseException 的区别:

    • Exception是大多数常见异常类的基类。这意味着大部分由于程序错误或意外情况引起的异常都继承自Exception类。例如,TypeErrorValueErrorIOError等都是Exception类的子类。
    • BaseException是所有异常类的根基类,是Exception类的父类。这意味着除了Exception类,还有其他异常类直接或间接地继承自BaseException。例如,SystemExitKeyboardInterrupt等都是直接继承自BaseException的异常类。

    因此,Exception是大多数常见异常的基类,而BaseException是所有异常的根基类。一般来说,在编写异常处理代码时,最好捕获Exception类而不是BaseException,以防止捕获到不应该处理的异常,如SystemExitKeyboardInterrupt

# 查看预定义的索引异常
>>> 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):			   # 相同处理方式的多种错误类型的写法
    针对错误类型23,对应的代码处理
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.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的对象,打开该压缩包文件。
常用的modeaction
'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 15 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 910 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 910 2018 hosts
	drwxr-xr-x 7 root root 4096 87 23:38 security

end

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值