​ —— B站 Python 课程自学笔记 【B站网课】

一、python简介

1、简介

python是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。

  • Python是解释型语言︰这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。

  • Python是交互式语言︰这意味着,您可以在一个Python提示符 >>> 后直接执行代码。

  • Python是面向对象语言:这意味着Python支持面向对象的风格或代码封装在对象的编程技术。

  • Python是初学者的语言:Python对初级程序员而言,是一种伟大的语言,它支持广泛的应用程序开发,从简单的文字处理到wwW浏览器再到游戏。

2、Python发展历史

Python是由Guido van Rossum在八十年代末和九十年代初,在荷兰国家数学和计算机科学研究所设计出来的。
Python本身也是由诸多其他语言发展而来的,这包括ABC、Modula-3、C、C++、Algol-68、SmalTalk、Unix shell和其他的脚本语言等等。
像Perl语言一样,Python源代码同样遵循GPL(GNU General Public License)协议。
现在Python是由一个核心开发团队在维护,Guido van Rossum仍然占据着至关重要的作用,指导其进展。Python 2.7被确定为最后一个Python 2.x版本,它除了支持 Python 2.x语法外,还支持部分Python 3.1语法。

3、python解释器

python3.8.0官网下载

python3.8.0百度网盘 提取码:kksk

安装流程:选择自定义安装(Customize installation),之后的有选项的全选,路径记得修改即可

安装好后,在命令行窗口输入

1
python --version

如下显示即安装成功

安装后的说明

4、Pycharm设置

(1)下载教程 下载地址

(2)代码模板设置

设置效果:

5、pip工具

Python自带,支持Python扩展库的安装,升级和卸载等操作

pip命令示例 说明
pip --version 显示版本和路径
pip --help 获取帮助
pip list 列出已安装的模块及其版本号
pip install SomePackage[==version] 在线安装SomePackage模块的指定版本
pip install SomePackage. whl 通过whl文件离线安装扩展库
pip install Package1, package2 ··· 依此(在线)安装Package1,Package2…
pip install -U SomePackage 升级SomePackage模块
pip uninstall SomePackage 卸载SomePackage模块
pip show SomePackage 显示已安装的包的信息

常见pip镜像源(国内源)

使用:

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyspider

或者全局设置:

1
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple

注意:如果存在多个python版本,则pip后面跟版本号,就可以指定使用哪一个,例如pip3.8 ...pip3.10 ...

二、基础知识

1、转义字符

字符 效果
\n 换行
\b 一个退格
\t tab
\\ \
\" "

原字符:不希望字符串中的 转义字符 起作用

使用:就是在字符串前加 rR

效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
print('hello\nworld')   # 1、\n : 换行
print('hello\tworld')
print('helloooo\nworld')
print('hello\rworld') # world 将 hello 进行了覆盖
print('hello\bworld') # \b 是一个退格
print('https:\\\\www.baidu.com')
print('老师说:\"大家好\"')

# "原字符":不希望字符串中的 转义字符 起作用;使用:就是在字符串前加 r 或 R
print(r'hello\nworld')
# 注意:最后一个字符不能是‘\’,但最后可以是‘\\’
# print(r'hello\nworld\') # 报错
print(r'hello\nworld\\')

输出:

1
2
3
4
5
6
7
8
9
10
11
hello
world
hello world
helloooo
world
world
hellworld
https:\\www.baidu.com
老师说:"大家好"
hello\nworld
hello\nworld\\

2、保留字

1
2
3
4
5
6
7
8
9
import keyword
# keyword.kwlist 共35个
i = 0
for key in keyword.kwlist:
if (i > 5):
i = 0
print('')
print(key, end="\t")
i = i + 1

输出结果:

1
2
3
4
5
6
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 yiel

3、标识符

变量、函数、类、模块和其它对象的起的名字就叫标识符

规则:

  • 字母、数字、下划线_
  • 不能以数字开头
  • 不能是保留字
  • ·严格区分大小写

4、变量

变量是内存中一个带标签的盒子

变量由三部分组成:

  • 标识: 表示对象所存储的内存地址,使用内置函数 id(obj) 来获取
  • 类型: 表示的是对象的数据类型,使用内置函数 type(obj) 来获取
  • : 表示对象所存储的具体数据,使用print(obj)可以将值进行打印输出
1
name = 'ggw'

在多次赋值后,变量名会指向新的空间

1
2
name = '马丽亚'
name = '楚溜冰'

5、数据类型

(1)整数类型

1
2
3
4
5
# 整数可以表示为二级制、十进制、八进制、十六进制
print('十进制', 10086)
print('二进制', 0b10101111) # 0b...
print('八进制', 0o176) # 0o...
print('十六进制', 0x1EAF) # 0x...

输出

1
2
3
4
十进制 10086
二进制 175
八进制 126
十六进制 7855

(2)浮点类型

  • 使用浮点数进行计算时,可能会出现小数点位数不精确的情况(因为计算机的二进制存储)
1
2
print(1.1 + 2.2)	# 输出为 3.3000000000000003
print(1.1 + 2.1) # 输出为 3.2
  • 解决方案:

导入模块decimal

1
2
from decimal import Decimal
print(Decimal('1.1') + Decimal('2.2')) # 输出为 3.3

(3)布尔类型

可以转化为整数:True = 1; False = 0.

1
2
3
4
f1 = True
f2 = False
print(f1 + 1) # 1 + 1 = 2
print(f2 + 1) # 0 + 1 = 1

(4)字符串类型

  • 字符串又被称为不可变的字符序列
  • 可以使用单引号’ ‘、双引号" "、三引号’‘’ ‘’'或"“” “”"来定义
  • 单引号和双引号定义的字符串必须在一行
  • 三引号定义的字符串可以分布在连续的多行
1
2
3
4
5
6
7
8
9
10
str1 = '人生苦短,我用Python'
str2 = "人生苦短,我用Python"
str3 = """人生苦短,我用Python"""
str4 = '''人生苦短,
2020 => 疫情
2021 => 疫情
2022 => 疫情
2023 => 疫情
我用Python'''
print(str1 + "\n" + str2 + "\n" + str3 + "\n" + str4)

输出:

1
2
3
4
5
6
7
8
9
人生苦短,我用Python
人生苦短,我用Python
人生苦短,我用Python
人生苦短,
2020 => 疫情
2021 => 疫情
2022 => 疫情
2023 => 疫情
我用Python

6、数据类型转换

(1)str()

将其他类型转化成字符串类型;

(2)int()

将其他类型转化成int类型;(抹零取整)

文字类'123'和小数'12.3'串(是字符串,但是他显示的是一个浮点数)无法转换;

(3)float()

将其他类型转化成float类型;

文字类无法转;

7、注释

1
2
3
4
5
6
7
8
9
10
# 单行注释

'''多

注释
'''

# 在文件开头加上中文声明注释,用以指定源码文件的编码格式
# coding:gbk
# coding后面的“:”,必须是中文的

效果

8、运算符

(1)算术运算符

运算符 表示
+
-
*
/
% 取余
** 幂运算
// 整数(一正一负,向下取整)print(11//2) # 输出为 5

(2)赋值运算符

  • 支持链式赋值: a = b = c = 20

  • 支持参数赋值:+=、-=、*=、/=、//=、%=

  • 支持系列解包赋值:a, b, c = 20, 30, 40

    1
    2
    3
    4
    # 交换两个变量的值
    a = 10
    b = 20
    a, b = b, a # a = 20, b = 10

(3)比较运算符

结果为bool类型

比较对象的标识用 is、 is not

1
2
a == b	# True: a 与 b 的value相同
a is b # True: a 与 b 的id标识相同

(4)布尔运算符

and、or、not、in、not in

1
2
3
4
5
6
# in、not in
str = 'helloworld'
print('w' in str)
print('k' in str)
print('w' not in str)
print('k' not in str)

输出为:

1
2
3
4
True
False
False
True

(5)位运算符

(6)运算符优先级

9、对象的布尔值

  • Python —切皆对象 ,所有对象都有一个布尔值。

  • 获取对象的布尔值,使用内置函数bool()

  • 以下对象的布尔值为False(其他均为True)

    • False

    • 数值0

    • None

    • 空字符串

    • 空列表 [] 、list()

    • 空元组 () 、tuple()

    • 空字典 {} 、dict()

    • 空集合 set()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 以下输出均为False
print(bool(False))
print(bool(0))
print(bool(0.0))
print(bool(None))
print(bool(''))
print(bool(""))
print(bool([])) # 空列表
print(bool(list()))
print(bool(())) # 空元组
print(bool(tuple()))
print(bool({})) # 空字典
print(bool(dict()))
print(bool(set())) # 空集合

10、pass语句

语句什么都不做,只是一个占位符,用在语法上需要语句的地方
什么时候使用:先搭建语法结构,还没想好代码怎么写的时候

1
2
3
4
5
ans = input('是否是会员?')
if ans == 'yes':
pass
else:
pass

11、内置函数

可以使用下列语句查看所有内置函数

1
dir(__builtins__)

可以使用help(函数名)查看某个函数的用法

(1)print()

1
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
参数 描述
objects 对象,表示可以一次输出多个对象。输出多个对象时,需要用 , 分隔
sep 用来间隔多个对象,默认值是一个空格
end 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符串
file 要写入的文件对象
flush 输出是否被缓存通常决定于 file,但如果 flush 关键字参数为 True,流会被强制刷新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1、输出数字
print(10086)

# 2、输出字符串
print('hello world')
print("hello world")

# 3、含有运算符的表达式
print(1 + 1)

# 4、将数据输出到文件中,ps: 盘符要存在, 'a+'文件不存在则创建,存在则追加
fp = open('C:/Users/GGW_2021/Desktop/笔记/python/text.txt', 'a+')
print('helloworld', file=fp)
fp.close()

# 5、不换行输出(输出内容在同一行上)
print('hello', 'world', 'Python')

问题:在运行Python文件时出现警告:PEP 8: W292 no newline at end of file
解决办法:在文件末尾加换行符(按回车即可)

(2)input()

变量 = input([提示语])

1
2
present = input('请输入:')		# 返回值为 字符串类型
print(present)

(3)range()

  • 用于生成一个整数序列
  • 返回值是一个迭代器对象

  • range类型的优点:不管range对象表示的整数序列有多长,所有range对象占用的内存空间都是相同的, 因为仅仅需要存储start,stop和step,只有当用到range对象时,才会去计算序列中的相关元素

  • in与not in判断整数序列中是否存在(不存在)指定的整数

  • 三种创建方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    """ 1、只有一个参数 """
    r = range(10) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 默认从 0 开始,默认相差1(步长)
    print(r) # range(0, 10)
    print(list(r)) # 用于查看 range 对象中的整数序列

    """ 2、两个参数 """
    r = range(1, 10) # range(start, stop, 默认相差1(步长))
    print(list(r)) # [1, 2, 3, 4, 5, 6, 7, 8, 9]

    """ 3、三个参数 """
    r = range(1, 10, 2) # range(start, stop, step)
    print(list(r)) # [1, 3, 5, 7, 9]

(4)eval()待续

12、不可变序列与可变序列

  • 不变可变序列:字符串、元组

    不变可变序列没有增、删,改的操作

  • 可变序列:列表、字典

    可变序列可以对序列执行增、删、改操作,对象地址不发生更改

1
2
3
4
str = 'hello'
print(id(str)) # 输出为 2464522942832
str += ' world'
print(id(str)) # 输出为 2464522942832

13、变量的作用域

  • 程序代码能访问该变量的区域
  • 根据变量的有效范围可分为
    • 局部变量:
      在函数内定义并使用的变量,只在函数内部有效
    • 全局变量:
      函数体外定义的变量,可作用于函数内外

局部变量使用global声明,这个变量就会就成全局变量

1
2
3
4
5
6
7
def fun(a):
global b
b = a


fun(10)
print(b) # 输出为 10

14、编码格式

常见的字符编码格式

  • Python的解释器使用的是Unicode(内存)
  • py文件在磁盘上使用UTF-8存储(外存)

指定文件的编码格式,utf-8是默认的

1
2
3
4
5
6
# 方法1: 在文件开头写上('#'也是要带的)
# coding:gbk
# coding后面的“:”,必须是中文的

# 方法2: 在文件开头写上('#'也是要带的)
# encoding=gbk

15、编程规范

  • \ 续行符

三、程序的组织结构

1、顺序结构

由上往下顺序执行

2、分支结构

(1)单分支结构

一个缩进表示层次结构

1
2
if 条件表达式:
条件执行体

(2)双分支结构

1
2
3
4
if 条件表达式:
条件执行体1
else:
条件执行体2

(3)多分支结构

1
2
3
4
5
6
7
8
if 条件表达式:
条件执行体1
elif:
条件执行体2
elif:
条件执行体N
[else]:
条件执行体N + 1

(4)嵌套使用if

1
2
3
4
5
6
7
if 条件表达式:
if 内层条件表达式:
内层条件执行体1
else:
内层条件执行体2
else:
条件执行体

(5)条件表达式

1
2
# 判断条件True: x, False: y 
x if 判断条件 else y

3、循环结构

(1)while

1
2
while 条件表达式:
条件执行体(循环体)

(2)for_in

1
2
for 自定义的变量 in 可迭代对象:
循环体

举例

如果不需要用到自定义变量,可写为’_’

1
2
3
4
5
6
7
8
9
10
for item in 'python':
print(item, end=" ")

print();
for item in range(10): # range()产生一个整数序列 -> 也是一个可迭代对象
print(item, end=" ")

print();
for _ in range(3): # 如果不需要用到自定义变量,可写为'_'
print('人生苦短,我用python')

输出:

1
2
3
4
5
p y t h o n 
0 1 2 3 4 5 6 7 8 9
人生苦短,我用python
人生苦短,我用python
人生苦短,我用python

(3)break语句、continue

  • break 用于结束循环;

  • continue 用于结束当前循环,进入下一循环。

(4)else语句和while、for_in搭配使用

  • 控制本层循环
  • 循环结束执行else

  • break跳出循环后不执行else

1
2
3
4
5
6
7
8
9
10
while ...:
...
else:
...


for ... in ...:
...
else:
...

举例:

1
2
3
4
5
6
7
8
9
10
11
for item in 'python':
print(item, end=" ")
else:
print()

i = 0
while i < 3 :
print("人生苦短,我学python")
i += 1
else:
print("我tm学好不好!")

输出

1
2
3
4
5
p y t h o n 
人生苦短,我学python
人生苦短,我学python
人生苦短,我学python
我tm学好不好!

四、列表、字典、元组、集合

1、列表

变量可以存储一个元素,而列表是一个“大容器”可以存储N多个元素,程序可以方便地对这些数据进行整体操作

(1)列表创建的方式

1
2
3
4
5
""" 1、使用[] """
lst1 = ['hello', 'world', 98]

""" 2、使用内置函数list() """
lst2 = list(['hello', 'world', 98])

(2)列表的特点

  • 列表元素按顺序有序排序

  • 是一个可变序列

  • 索引映射唯一个数据

  • 列表可以存储重复数据

  • 任意数据类型混存

  • 根据需要动态分配和回收内存

(3)内存

1
2
3
4
5
lst = ['hello', 'world', 98]
print("", id(lst), "\n",\
id(lst[0]), "\n",\
id(lst[1]), "\n",\
id(lst[2]))

输出结果

1
2
3
4
2769239388736 
2769239324848
2769239325040
2769238035728

(4)获取、切片

  • 获取列表指定元素的索引 index()

    • 如查列表中存在N个相同元素,只返回相同元素中的第一个元素的索引

    • 如果查询的元素在列表中不存在,则会抛出ValueError

    • 还可以在指定的start和stop之间进行查找

    • index(‘目标’, start, end) # start~end-1 指定范围

      1
      2
      3
      4
      lst = ['hello', 'world', 98]
      print(lst.index('hello')) # 0
      print(lst.index('python')) # ValueError: 'python' is not in list
      print(lst.index('hello',1,3)) # ValueError: 'hello' is not in list
  • 根据索引获取元素

    • 正向索引从 0 到 N - 1

    • 逆向索引从 -N 到 -1

    • 指定索引不存,抛出 indexError

      1
      2
      3
      4
      lst = ['hello', 'world', 98]
      print(lst[0]) # hello
      print(lst[-1]) # 98
      print(lst[3]) # IndexError: list index out of range
  • 切片操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    lst = [1, 2, 3, 4, 5, 6, 7, 8]
    print('原列表', id(lst)) # 2016570503552
    print('新列表', id(lst[1:6:1])) # 2016570470144
    # 默认步长为 1
    print(lst[1:6]) # [2, 3, 4, 5, 6]
    # 默认start
    print(lst[:6:2]) # [1, 3, 5]
    # 默认stop
    print(lst[1::2]) # [2, 4, 6, 8]

    """ step为负数 """
    print(lst[::-1]) # [8, 7, 6, 5, 4, 3, 2, 1]
    print(lst[7::-2]) # [8, 6, 4, 2]
    print(lst[6:0:-2]) # [7, 5, 3]

(5)查询列表、遍历

  • 判断指定元素是否在列表中

    元素 in 列表名

    元素 not in 列表名

  • 列表元素的遍历

    1
    2
    for 迭代对象 in 列表名:
    操作
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 示例:
    lst = [1, 2, 3, 4, 5, 6, 7, 8]
    print(1 in lst) # True
    print(10 in lst) # False
    print(1 not in lst) # False
    print(10 not in lst) # True

    # 循环遍历
    for item in lst:
    print(item)

(6)添加

方法 描述
append() 在列表末尾添加一个元素
extend() 在列表末尾添加至少一个元素
insert() 在列表任意指定位置添加一个元素
切片 在列表任意指定位置添加至少一个元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
lst1 = [10, 20, 30]
print("原列表:", id(lst1)) # 输出为 1814123508096
lst1.append(40)
print("新列表:", id(lst1)) # 输出为 1814123508096

# ========================================================================
lst2 = ['hello', 'world']
# lst1.append(lst2)
# 将lst2作为一个元素添加到列表的末尾 [10, 20, 30, 40, ['hello', 'world']]
# 向列表末尾一次性添加多个元素
lst1.extend(lst2)
print(lst1) # 输出为 [10, 20, 30, 40, 'hello', 'world']

# ========================================================================
# 指定位置添加元素
lst1.insert(1, 90)
print(lst1) # 输出为 [10, 90, 20, 30, 40, 'hello', 'world']

# ========================================================================
# 在任意位置添加多个元素
lst3 = ['ggw', 'xpl']
lst1[1:] = lst3 = ['ggw', 'xpl']
print(lst1) # 输出为 [10, 'ggw', 'xpl']

(7)删除

方法 描述
remove() 一次删除一个元素;
重复元素只删除第一个;
元素不存在抛出ValueError;
pop() 删除一个指定索引位置上的元素;
指定索引不存在抛出IndexError;
不指定索引,删除列表最后一个元素;
切片 一次至少删除一个元素
clear() 清空列表
del 删除列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
lst = [10, 20, 30, 40, 50, 60, 70, 80]
lst.remove(30)
print(lst) # 输出为 [10, 20, 40, 50, 60, 70, 80]

# ========================================================================
lst.pop(1)
print(lst) # 输出为 [10, 40, 50, 60, 70, 80]
# lst.pop(6)
# print(lst) # IndexError: pop index out of range
lst.pop()
print(lst) # 输出为 [10, 40, 50, 60, 70] 默认删除最后一个

# ========================================================================
new_lst = lst[1:3]
print(new_lst, lst) # 输出为 [40, 50] [10, 40, 50, 60, 70]
# 切片删除
lst[1:3] = []
print(lst) # 输出为 [10, 60, 70]

# ========================================================================
lst.clear()
print(lst) # 输出为 []

# ========================================================================
# del lst
# print(lst)
# NameError: name 'lst' is not defined. Did you mean: 'list'?

(8)修改

  • 为指定索引的元素赋予一个新值
  • 为指定的切片赋予一个新值
1
2
3
4
5
6
7
lst = [10, 20, 30, 40]
# 一次修改一个值
lst[2] = 100
print(lst) # 输出为 [10, 20, 100, 40]
# 一次修改多个值
lst[1:3] = [200, 300]
print(lst) # 输出为 [10, 200, 300, 40]

(9)排序和列表生成式

排序

  • 调用 sort() 方法,列有中的所有元素默认按照从小到大的顺序进行排序,可以指定reverse=True,进行降序排序

  • 调用内置函数 sorted() ,可以指定reverse=True,进行降序排序,原列表不发生改变,产生新的列表对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    lst1 = [20, 40, 10, 98, 54]
    print('排序前', lst1, id(lst1)) # 输出为 [20, 40, 10, 98, 54] 1776600150400
    # 开始排序,调用列表对象的 sort 方法
    lst1.sort()
    print('排序后', lst1, id(lst1)) # 输出为 [10, 20, 40, 54, 98] 1776600150400
    # 使用参数 reverse = True 降序, 默认为False
    lst1.sort(reverse=True)
    print(lst1) # 输出为 [98, 54, 40, 20, 10]

    # ============================================================================
    lst2 = [20, 40, 10, 98, 54]
    new_lst2 = sorted(lst2)
    print(lst2, id(lst2)) # 输出为 [20, 40, 10, 98, 54] 2450901070336
    print(new_lst2, id(new_lst2)) # 输出为 [10, 20, 40, 54, 98] 2450901022144
    # 指定关键字参数,降序
    desc_lst2 = sorted(lst2, reverse=True)
    print(desc_lst2) # 输出为 [98, 54, 40, 20, 10]

列表生成式

生成列表的公式

语法格式:

ps:“表示列表元素的表达式"中通常包含自定义变量

1
2
3
4
5
6
7
8
lst = [i for i in range(1, 10)]
print(lst) # 输出为 [1, 2, 3, 4, 5, 6, 7, 8, 9]

lst = [i*i for i in range(1, 10)]
print(lst) # 输出为 [1, 4, 9, 16, 25, 36, 49, 64, 81]

lst = [i*2 for i in range(1, 10)]
print(lst) # 输出为 [2, 4, 6, 8, 10, 12, 14, 16, 18]

查看扩展内容

列表生成式的基本语法格式如下:

1
new_list = [expression for item in iterable if condition]

其中:

  • expression 是对 item 的操作或表达式,用于生成新的元素。
  • item 是迭代的元素。
  • iterable 是可迭代对象,如列表、元组、字符串等。
  • condition 是一个可选的条件,用于过滤元素。只有满足条件的元素才会被包含在新列表中。

可以根据需要省略 if condition 部分,只保留 expression for item in iterable

以下是一些示例:

  1. 生成一个包含 0 到 9 的平方的列表:
1
2
squares = [x**2 for x in range(10)]
print(squares)
  1. 生成一个包含 0 到 9 的平方的列表,但只保留偶数:
1
2
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)
  1. 将列表中的字符串转换为大写:
1
2
3
words = ['apple', 'banana', 'cherry']
uppercase_words = [word.upper() for word in words]
print(uppercase_words)
  1. 使用 if-else 语句生成一个包含奇数和偶数的列表,但奇数变为字符串形式:
1
2
3
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = [str(x) if x % 2 != 0 else x for x in numbers]
print(result)

这些示例演示了列表生成式的基本用法,你可以根据需要对其进行扩展和调整。

对最后一个例子进行解释

这个列表生成式的语法结构是:

1
new_list = [expression_if_true if condition else expression_if_false for item in iterable]

在这个例子中:

  • expression_if_true 是在满足条件 x % 2 != 0 时对 x 进行的操作,即将奇数转换为字符串形式。
  • condition 是判断是否应该执行 expression_if_true 的条件。
  • expression_if_false 是在条件不满足时对 x 进行的操作,即保持原值。
  • item 是迭代的元素,这里是 x
  • iterable 是可迭代对象,这里是 numbers

因此,这个列表生成式的作用是遍历 numbers 中的每个元素 x,如果 x 是奇数(满足条件 x % 2 != 0),则将其转换为字符串形式;如果 x 是偶数,则保持原值。生成的列表就是经过这样处理后的结果。

这是一个在列表生成式中使用 if-else 语句的示例。


2、字典

(1)什么是字典

  • Python内置的数据结构之一,与列表一样是一个可变序列
  • 以键值对的方式存储数据,字典是一个无序的序列

(2)实现原理

字典的实现原理与查字典类似,查字典是先根据部首或拼音查找应的页码,Python中的字典是根据key查找value所在的位置

字典示意图:

(3)创建

  • 最常用:使用{}

    scores = {'张三': 100, '李四': 98, '王五': 45}

  • 使用内置函数dict()

    scores = dict(张三='100', 李四='98', 王五='45')

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    """ 1、使用{}创建字典 """
    scores = {'张三': 100, '李四': 98, '王五': 45}
    print(scores) # 输出为 {'张三': 100, '李四': 98, '王五': 45}
    print(type(scores)) # 输出为 <class 'dict'>

    """ 2、dict() """
    scores = dict(张三='100', 李四='98', 王五='45')
    print(scores) # 输出为 {'张三': '100', '李四': '98', '王五': '45'}

    """ 空字典 """
    scores = {}
    print(scores) # 输出为 {}

(4)获取

  • []

    scores['张三']

  • get()

    scores.get('张三')

  • 区别

    • 如果字典中不存在指定的key,抛出keyError异常

    • get()方法取值,如果字典中不存在指定的key,并不会抛出KeyErre
      None,可以通过参数设置默认的value,以便指定的key不存在时返回

      get(key[, 默认值])

      1
      2
      3
      4
      5
      scores = {'张三': 100, '李四': 98, '王五': 45}
      # print(scores['ggw']) # 输出为 KeyError: 'ggw'
      print(scores.get('ggw')) # 输出为 None
      print(scores.get('ggw', '不造啊')) # 输出为 不造啊
      print(scores.get('ggw', 404)) # 输出为 404

(5)增删改查

  • 判断:in \ not in (key)
  • 删除:del scores[‘张三’]
  • 新增:scores[‘ggw’] = 99
  • 修改:scores[‘ggw’] = 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
scores = {'张三': 100, '李四': 98, '王五': 45}

# 判断
print('张三' in scores) # 输出为 True
print('张三' not in scores) # 输出为 False

# 删除
del scores['张三']
print(scores) # 输出为 {'李四': 98, '王五': 45}

# 新增
scores['ggw'] = 99
print(scores) # 输出为 {'李四': 98, '王五': 45, 'ggw': 99}

# 修改
scores['ggw'] = 100
print(scores) # 输出为 {'李四': 98, '王五': 45, 'ggw': 100}

(6)常用方法

方法 描述
keys() 获取字典中所有的key
values() 获取字典中所有的value
items() 获取字典中所有的key, value对
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
scores = {'张三': 100, '李四': 98, '王五': 45}

# 获取字典中所有的key
keys = scores.keys()
print(keys) # 输出为 dict_keys(['张三', '李四', '王五'])
print(type(keys)) # 输出为 <class 'dict_keys'>
print(list(keys)) # 输出为 ['张三', '李四', '王五'] 转成列表

# 获取字典中所有的value
values = scores.values()
print(values) # 输出为 dict_values([100, 98, 45])
print(type(values)) # 输出为 <class 'dict_values'>
print(list(values)) # 输出为 [100, 98, 45]

# 获取字典中所有的key, value对
items = scores.items()
print(items) # 输出为 dict_items([('张三', 100), ('李四', 98), ('王五', 45)])
print(type(items)) # 输出为 <class 'dict_items'>
print(list(items)) # 输出为 [('张三', 100), ('李四', 98), ('王五', 45)] 转成元组

(7)遍历

1
2
3
4
5
6
7
8
9
10
scores = {'张三': 100, '李四': 98, '王五': 45}
# 遍历
for item in scores:
print(item, scores[item], scores.get(item))
# 输出为
"""
张三 100 100
李四 98 98
王五 45 45
"""

(8)特点

  • 字典中的所有元素都是一个key-value对, key不允许重复, value可以重复
  • 字典中的元素是无序的
  • 字典中的key必须是不可变对象,字典也可以根据需要动态地伸缩
  • 字典会浪费较大的内存,是一种使用空间换时间的数据结构

(9)字典生成式

内置函数zip()
用于将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,然后返回由这些元组组成的列表

1
2
3
4
5
6
items = ['Fruits', 'Books', 'Others']
prices = [96, 33, 22, 56, 76]
res1 = {item: price for item, price in zip(items, prices)}
print(res1) # 输出为 {'Fruits': 96, 'Books': 33, 'Others': 22}
res2 = {item.upper(): price for item, price in zip(items, prices)}
print(res2) # 输出为 {'FRUITS': 96, 'BOOKS': 33, 'OTHERS': 22}

3、元组

Python内置的数据结构之一,是一个不可变序列

(1)创建

  • 小括号()
  • 使用内置函数 tuple()
  • 只包含一个元组的元素需要使用逗号和小括号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1、小括号()
t1 = ('python', 'hello', 90)
print(t1) # 输出为('python', 'hello', 90)
print(type(t1)) # 输出为<class 'tuple'>

# 2、使用内置函数 tuple()
t2 = tuple(('python', 'hello', 90))
print(t2) # 输出为('python', 'hello', 90)
print(type(t2)) # 输出为<class 'tuple'>

# 3、只包含一个元组的元素需要使用逗号和小括号
t3 = ('hello')
print(t3) # 输出为hello
print(type(t3)) # 输出为<class 'str'>
t4 = ('hello', )
print(t4) # 输出为('hello',)
print(type(t4)) # 输出为<class 'tuple'>

# 4、创建空元组
t5 = ()
t6 = tuple()
print(t5, t6) # 输出为 () ()

(2)为什么元组要设计成不可变的序列

  • 在多任务环境下,同时操作对象时不需要加锁

  • 因此,在程序中尽量使用不可变序列

  • 注意事项: 元组中存储的是对象的引用

    • 如果元组中对象本身不可对象,则不能再引用其它对象
    • 如果元组中的对象是可变对象,则可变对象的引用不允许改变,但数据可以改变

1
2
3
4
5
t = (10, [20, 30], 40)
# 元组不允许修改元素
# t[1] = 100 # 输出为 TypeError: 'tuple' object does not support item assignment
t[1].append(35)
print(t) # 输出为 (10, [20, 30, 35], 40)

(3)获取、遍历

1
2
3
4
5
6
7
8
9
10
11
t = (10, [20, 30], 40)

# 使用索引获取元组元素
print(t[0]) # 输出为 10
print(t[1]) # 输出为 [20, 30]
print(t[2]) # 输出为 40
# print(t[3]) # 输出为 IndexError: tuple index out of range

# 遍历元组
for item in t:
print(item)

4、集合

  • Python语言提供的内置数据结构
  • 与列表、字典―样都属于可变类型的序列
  • 集合是没有value的字典

(1)创建

  • 花括号{}

    s = {1, 2, 4, 5, 5, 7, 7}

  • 使用内置函数set()

    s = set(range(6))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
""" 1、花括号{} """
# 集合元素不允许重复
s = {1, 2, 4, 5, 5, 7, 7}
print(s) # 输出为 {1, 2, 4, 5, 7}

""" 2、使用内置函数set() """
s = set(range(6))
print(s) # 输出为 {0, 1, 2, 3, 4, 5}
print(set([3, 4, 53, 56])) # 输出为 {56, 3, 4, 53}
print(set((3, 4, 53, 56))) # 输出为 {56, 3, 4, 53}
print(set('python')) # 输出为 {'y', 'p', 'n', 't', 'o', 'h'}
print(set({3, 4, 53, 56, 4, 4})) # 输出为 {56, 3, 4, 53}

""" 3、空集合 """
s1 = {}
s2 = set()
print(s1, type(s1)) # 输出为 {} <class 'dict'>
print(s2, type(s2)) # 输出为 set() <class 'set'>

(2)增删改查

  • 集合元素的判断操作

    in或not in

  • 集合元素的新增操作

    方法 描述
    add() 一次添加一个元素
    update() 至少添加一个元素
  • 集合元素的删除操作

    方法 描述
    remove() 一次删除一个指定元素,如果指定的元素不存在抛出KeyError
    discard() 一次删除一个指定元素,如果指定的元素不存在不抛出异常
    pop() 一次只删除一个任意元素
    clear() 清空集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
s = {10, 20, 30, 405, 60}
""" 判断操作 """
print(10 in s) # 输出为 True
print(100 not in s) # 输出为 True

""" 新增操作 """
s.add(80)
print(s) # 输出为 {80, 20, 405, 10, 60, 30}
s.update({200, 400, 300})
print(s) # 输出为 {200, 10, 300, 80, 400, 20, 405, 60, 30}
s.update(([100, 99, 8]))
print(s) # 输出为 {99, 100, 200, 8, 10, 300, 80, 400, 20, 405, 60, 30}
s.update((78, 64, 56))
print(s) # 输出为 {64, 99, 100, 200, 8, 10, 300, 78, 80, 400, 20, 405, 56, 60, 30}

""" 删除操作 """
s.remove(100)
print(s) # 输出为 {64, 99, 200, 8, 10, 300, 78, 80, 400, 20, 405, 56, 60, 30}
# s.remove(500) # 输出为 KeyError: 500
s.discard(500)
s.discard(300)
print(s) # 输出为 {64, 99, 200, 8, 10, 78, 80, 400, 20, 405, 56, 60, 30}
s.pop() # 输出为 无参
print(s) # 输出为 {99, 200, 8, 10, 78, 80, 400, 20, 405, 56, 60, 30}
s.clear()
print(s) # 输出为 set()

(3)集合间的关系

  • 两个集合是否相等

    • 可以使用运算符==或!=进行判断
  • 一个集合是否是另一个集合的子集

    • 可以调用方法 issubset() 进行判断

    • B是A的子集

  • 一个集合是否是另一个集合的超集

    • 可以调用方法 issuperset() 进行判断·

    • A是B的超集

  • 两个集合是否没有交集

    • 可以调用方法 isdisjoint() 进行判断,有交集为False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
s1 = {10, 20, 30, 40}
s2 = {30, 40, 20, 10}
""" 两个集合是否相等 """
print(s1 == s2) # 输出为 True
print(s1 != s2) # 输出为 False

""" 一个集合是否是另一个集合的子集 """
s1 = {10, 20, 30, 40, 50, 60}
s2 = {10, 20, 30, 40}
s3 = {10, 20, 90}
print(s2.issubset(s1)) # 输出为 True
print(s3.issubset(s1)) # 输出为 False

""" 一个集合是否是另一个集合的超集 """
print(s1.issuperset(s2)) # 输出为 True
print(s1.issuperset(s3)) # 输出为 False

""" 两个集合是否有交集 """
print(s2.isdisjoint(s3)) # 输出为 False (有交集为False)
s4 = {100, 200}
print(s2.isdisjoint(s4)) # 输出为 True (无交集为True)

(4)集合间的数学操作

  1. 交集:s1.intersection(s2) 或者 s1 & s2

  2. 并集:s1.union(s2) 或者 s1 | s2

  3. 差集:s1.difference(s2) 或者 s1 - s2

  4. 对称差集:s1.symmetric_difference(s2)或者 s1 ^ s2

    ps:原集合都没有变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
s1 = {10, 20, 30, 40}
s2 = {20, 30, 40, 50}
# 1、交集
print(s1.intersection(s2))
print(s1 & s2) # 输出为 {40, 20, 30}

# 2、并集
print(s1.union(s2))
print(s1 | s2) # 输出为 {40, 10, 50, 20, 30}

# 3、差集
print(s1.difference(s2))
print(s1 - s2) # 输出为 {10}

# 4、对称差集
print(s1.symmetric_difference(s2))
print(s1 ^ s2) # 输出为 {10, 50}

(5)集合生成式

1
2
s = {i*i for i in range(10)}
print(s) # {0, 1, 64, 4, 36, 9, 16, 49, 81, 25}

5、总结

五、字符串

在Python中字符串是基本数据类型,是一个不可变的字符序列

1、字符串的驻留机制

仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串的驻留池中,Python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量

1
2
3
4
5
6
a = 'Python'
b = "Python"
c = '''Python'''
print(a, id(a)) # Python 1937251321008
print(b, id(b)) # Python 1937251321008
print(c, id(c)) # Python 1937251321008
  • 触发驻留机制的几种情况(交互模式)

    • 字符串的长度为0或1时
    • 符合标识符的字符串
    • 字符串只在编译时进行驻留,而非运行时
    • [-5,256]之间的整数数字
  • sys中的intern方法强制2个字符串指向同一个对象

  • PyCharm对字符串进行了优化处理(只要内容相同即驻留)

  • 字符串驻留机制的优缺点

    • 当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是会比较影响性能的。
    • 需要进行字符串拼接时,建议使用str类型的join方法,而非+ ,因为join()方法是先计算出所有字符中的长度,然后再拷贝,只new一次对象,效率要比"+"效率高

2、字符串的常用操作

(1)查询

方法 描述
index() 查找子串substr第一次出现的位置,如果查找的子串不存在时,则抛出ValueError
rindex() 查找子串substr最后一次出现的位置,如果查找的子串不存在时,则抛出ValueError
find() 查找子串substr第一次出现的位置,如果查找的子串不存在时,则返回 -1
rfind() 查找子串substr最后一次出现的位置,如果查找的子串不存在时,则返回 -1
1
2
3
4
5
s = 'hello, hello'
print(s.index('lo')) # 输出为 3
print(s.find('lo')) # 输出为 3
print(s.rindex('lo')) # 输出为 10
print(s.rfind('lo')) # 输出为 10

(2)大小写转换

方法 描述
upper() 把字符串中所有字符都转成大写字母;
产生了新的字符串
lower() 把字符串中所有字符都转成小写字母;
产生了新的字符串
swapcase() 把字符串中所有大写字母转成小写字母,把所有小写字母都转成大写字母;
产生了新的字符串
capitalize() 把第一个字符转换为大写,把其余字符转换为小写;
产生了新的字符串
title() 把每个单词的第一个字符转换为大写,把每个单词的剩余字符转换为小写;
产生了新的字符串

(3)字符串对齐

方法 描述
center() 居中对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则则返回原字符串
ljust() 左对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则则返回原字符串
rjust() 右对齐,第1个参数指定宽度,第2个参数指定填充符,第2个参数是可选的,默认是空格,如果设置宽度小于实际宽度则则返回原字符串
zfill() 右对齐,左边用0填充,该方法只接收一个参数,用于指定字符串的宽度,如果指定的宽度小于等于字符串的长度,返回字符串本身
1
2
3
4
5
s = 'hello, python'
print(s.center(20, '*')) # 输出为 ***hello, python****
print(s.center(10, '*')) # 输出为 hello, python
print(s.zfill(20)) # 输出为 0000000hello, python
print(s.zfill(10)) # 输出为 hello, python

(4)字符串的分割

方法 描述
split() 从字符串的边开始劈分,默认的劈分字符是空格字符串,返回的值都是一个列表
以通过参数sep指定劈分字符串是的劈分符;
通过参数maxsplit指定劈分字符串时的最大劈分次数,在经过最大次劈分之后,剩余的子串会单独做为一部分
rsplit() 从字符串的边开始劈分,其他同split()
1
2
3
4
5
6
7
s1 = 'hello world python'
print(s1.split()) # 输出为 ['hello', 'world', 'python']
s2 = 'hello|world|python'
print(s2.split()) # 输出为 ['hello|world|python']
print(s2.split(sep='|')) # 输出为 ['hello', 'world', 'python']
print(s2.split(sep='|', maxsplit=1)) # 输出为 ['hello', 'world|python']
print(s2.rsplit(sep='|', maxsplit=1)) # 输出为 ['hello|world', 'python']

ps: 可以这么写'hello|world|python'.split('|')'

(5)判断字符串

方法 描述
isidentifier() 判断指定的家符串是不是合法的标识符
isspace() 判断指定的字符串是否全部由空白字符组成(回车、换行,水平制表符)
isalpha() 判断指定的字符串是否全部由字母组成(汉字也是)
isdecimal() 判断指定字符串是否全部由十进制的数字组成
isnumeric() 判断指定的字符串是否全部由数字组成
isalnum() 判断指定字符串是否全部由字母和数字组成

(6)字符串的替换与合并

方法 描述
replace() 第1个参数指定被替换的子串,第2个参数指定替换子串的字符串,该方法返回替换后得到的字符串,替换前的字符串不发生变化,调用该方法时可以通过第3个参数指定最大替换次数
省流:第1个参数:替换什么;第2个参数:替换成什么;第3个参数:最大替换几次;
join() 列表或元组中的字符串合并成一个字符串
1
2
3
4
5
6
7
8
9
10
""" 替换 """
s = 'hello world python'
print(s.replace('python', 'java')) # hello world java
print(s.replace('l', 'x', 2)) # hexxo world python 将列表或元组中的字符串合并成一个字符串

""" 合并 """
lst = ['hello', 'world', 'python']
print(''.join(lst)) # helloworldpython
print(' | '.join(lst)) # hello | world | python
print('*'.join('python')) # p*y*t*h*o*n

3、字符串的比较操作

  • 运算符: >, >=, <, <=, ==, !=
  • 比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符,依次比较下去,直到两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串中的所有后续字符将不再被比较。
  • 比较原理:两上字符进行比较时,比较的是其ordinal value(原始值),调用内置函数 ord() 可以得到指定字符的ordinal value。与内置函数ord()对应的是内置函数 chr() ,调用内置函数 chr() 时指定ordinal value可以得到其对应的字符。
1
2
3
4
print('abc' > 'abs')        # 输出为 False
print('a' < 'b') # 输出为 True
print(ord('a'), ord('b')) # 输出为 97 98
print(chr(97), chr(98)) # 输出为 a b

4、字符串的切片操作

  • 字符串是不可变类型
    • 不具备增、删、改等操作
    • 切片操作将产生新的对象

切片操作同列表str[start: end: step]

1
2
3
4
5
6
7
8
9
str = 'hellopython'
s1 = str[:4]
s2 = str[5:]
s3 = s1 + ' ' + s2 + '!'
print(s1, '|', s2, '|', s3)
print('', id(str), '\n', \
id(s1), '\n', \
id(s2), '\n', \
id(s3))

输出结果

1
2
3
4
5
hell | python | hell python!
2638999304560
2638999304368
2638999351984
2638999351664

5、格式化字符串

两种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name = '张三'
age = 20

""" 1、%占位符 """
print('我叫%s, 今年%d岁' % (name, age))

""" 2、{}占位符 """
print('我叫{0}, 今年{1}岁'.format(name, age))

""" 3、f-string """
print(f'我叫{name}, 今年{age}岁')

""" 精度 """
print('%10d' % 99) # 10表示的是宽度 | 99
print('%.3f' % 3.1415926) # 3表示的是小数点后3位 |3.142
print('%10.3f' % 3.1415926) # | 3.142

print('{0:.3}'.format(3.1415926)) # 3表示的是一个三位 |3.14
print('{0:.3f}'.format(3.1415926)) # 3表示的是一个三位小数 |3.142
print('{0:10.3f}'.format(3.1415926)) # | 3.142

输出结果

1
2
3
4
5
6
7
8
9
我叫张三, 今年20岁
我叫张三, 今年20岁
我叫张三, 今年20岁
99
3.142
3.142
3.14
3.142
3.142

6、编码、解码

  • 为什么需要编码转换

  • 编码解码的方式

    • 编码:将字符串转换为二进制数据(bytes),s.encode(encoding='GBK')GBK、UTF-8
    • 解码:将bytes类型的数据转换成字符串类型,byte.decode(encoding='GBK'),编码解码的格式要一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
s = '不想学了'
""" 编码 """
print(s.encode(encoding='GBK')) # GBK:一个中文占两个字节
# 输出:b'\xb2\xbb\xcf\xeb\xd1\xa7\xc1\xcb'
print(s.encode(encoding='UTF-8')) # UTF-8:一个中文占三个字节
# 输出:b'\xe4\xb8\x8d\xe6\x83\xb3\xe5\xad\xa6\xe4\xba\x86'

""" 解码 格式要一致"""
byte = s.encode(encoding='GBK')
print(byte.decode(encoding='GBK'))
# 输出为 不想学了
byte = s.encode(encoding='UTF-8')
print(byte.decode(encoding='UTF-8'))
# 输出为 不想学了

六、函数

1、创建

1
2
3
def 函数名([输入参数]):
函数体
[return 返回值]

示例:

1
2
3
4
5
6
7
8
9
""" 函数创建 """
def calc(a, b): # a, b是形参
c = a + b
return c


""" 函数调用 """
res = calc(10, 20)
print(res) # 输出为 30

2、函数调用的参数传递

  • 位置实参
    根据形参对应的位置进行实参传递
  • 关键字实参
    根据形参名称进行实参传递
1
2
3
4
5
6
def _put(a, b):     # a, b是形参
print('a =', a, 'b =', b)


_put(10, 20) # a = 10 b = 20
_put(b=10, a=20) # a = 20 b = 10

3、参数传递的内存分析

内存分析图:

4、函数的返回值

  • 如果函数没有返回值【函数执行完毕之后,不需要给调用处提供数据】return可以省略不写

    如果没有return,则默认返回None

  • 函数的返回值如果是1个,直接返回类型

  • 函数的返回值如果是多个(return a, b),返回的结果为元组

1
2
3
4
5
6
7
8
9
10
11
def fun1():
print("执行了fun1")


def fun2():
print("执行了fun2")
return 10, 20


print(fun1())
print(fun2(), type(fun2()))

输出结果

1
2
3
4
5
执行了fun1
None
执行了fun2
执行了fun2
(10, 20) <class 'tuple'>

5、函数参数的定义

(1)默认值参数

函数定义时,给形参设置默认值,只有与默认值不符的时候才需要传递实参
举例:

1
2
3
4
5
def fun(a, b=10):
print(a, b)


fun(1) # 输出为 1 10

(2)个数可变的位置参数

  • 定义函数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置参数
  • 使用 * 定义个数可变的位置形参
  • 结果为一个元组
1
2
3
4
5
6
def put(*args):
print(args)


put(10) # 输出为 (10,)
put(10, 20, 30) # 输出为 (10, 20, 30)

(3)个数可变的关键字形参

  • 定义函数时,无法事先确定传递的关键字实参的个数时,使用可变的关键字形参
  • 使用 ** 定义个数可变的关键字形参
  • 结果为一个字典
1
2
3
4
5
6
def _put(**args):
print(args)


_put(a=10) # {'a': 10}
_put(a=10, b=20, c=30) # {'a': 10, 'b': 20, 'c': 30}

ps:

  • 个数可变的位置参数和关键字形参都只能是一个
  • 可以同时都有,但是个数可变的位置参数必须在写在前面
1
2
3
4
def _put(*args, *a):	# 报错
def _put(**args, **a): # 报错
def _put(**args, *a): # 报错
def _put(*args, **a): # 正确

(4)参数使用总结

视频总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def put(a, b, c):
print('a =', a, ', b =', b, ', c =', c)


""" 将 列表 每个元素转化为 位置实参 传入"""
lst = [100, 200, 300]
# put(lst) # 输出为 TypeError
# 解构列表
put(*lst) # 输出为 a = 100 , b = 200 , c = 300

""" 将 字典 每个元素转化为 关键字实参 传入"""
dic = {'a': 111, 'b': 222, 'c': 333}
# put(dic) # 输出为 TypeError
put(*dic) # 输出为 a = a , b = b , c = c
put(**dic) # 输出为 a = 111 , b = 222 , c = 333


""" 函数定义时的形参顺序问题 """
def fun1(a, b, *, c, d): # '*'后必须使用 关键字实参
pass
def fun2(a, b, *, c, d, **args):
pass
def fun3(a, b=10 ,*args1 ,**args2):
pass

6、递归函数

  • 递归的调用过程:

    • 每递归调用一次函数,都会在栈内存分配一个栈帧,

    • 每执行完一次函数,都会释放相应的空间

1
2
3
4
5
6
7
8
def fac(n):                       
if n == 1:
return 1
else:
return n * fac(n - 1)


print(fac(6)) # 720 6的阶乘

7、匿名函数

使用lambda来创建匿名函数,它是一个可以接收多个任意参数,并返回单个表达式的值的函数

1
2
3
4
f = lambda x, y, z: x * y * z
print(f(3, 4, 5)) # 60
L = lambda x: [x**2, x**3, x**4]
print(L(2)) # [4, 8, 16]

七、bug、异常处理

1、bug的类型

  • 粗心导致的语法错误

    1. 漏了末尾的冒号,如if语句,循环语句,else子句等
    2. 缩进错误,该缩进的没缩进,不该缩进的瞎缩进
    3. 英文符号写成中文符号,比如说:引号,冒号,括号
    4. 字符串拼接的时候,把字符串和数字拼在一起
    5. 没有定义变量,比如说while的循环条件的变量
    6. "=="比较运算符和”=”赋值运算符的混用
  • 知识点掌握不熟练

    • 索引越界
    • 内置函数还是对象方法
  • 逻辑错误

  • 被动掉坑

    程序代码逻辑没有错,只是因为用户错误操作或者一些“例外情况"而导致的程序崩溃

    解决:Python异常处理机制

2、Python异常处理机制

Python提供了异常处理机制,可以在异常出现时即时捕获,然后内部“消化”,让程序继续运行。

(1)try-except

(2)多个except结构

  • 捕获异常的顺序按照先子类后父亲类的顺序,为了避免遗漏可能出现的异常,可以在最后增加

    BaseException

1
2
3
4
5
6
7
8
9
10
11
try:
n1 = int(input('请输入第一个整数:'))
n2 = int(input('请输入第二个整数:'))
res = n1 / n2
print('结果为:', res)
except ZeroDivisionError:
print('除数不能为0')
except ValueError:
print('请输入数字')
except BaseException:
print('error')

(3)try-except-else

如果try块中没有抛出异常,则执行else块,如果try中抛出异常,则执行except块

1
2
3
4
5
6
7
8
try:
n1 = int(input('请输入第一个整数:'))
n2 = int(input('请输入第二个整数:'))
res = n1 / n2
except BaseException as e:
print('出错了:', e)
else:
print('结果为:', res)

(4)try-except-else-finally

finally块无论是否发生异常都会被执行,能常用来释放try块中申请的资源

1
2
3
4
5
6
7
8
9
10
try:
n1 = int(input('请输入第一个整数:'))
n2 = int(input('请输入第二个整数:'))
res = n1 / n2
except BaseException as e:
print('出错了:', e)
else:
print('结果为:', res)
finally:
print('运行结束')

3、Python中常见的异常

异常类型 描述
ZeroDivisionError 除(或取模)零(所有数据类型)
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
NameError 未声明/初始化对象(没有属性)
SyntaxError Python语法错误
ValueError 传入无效参数

4、traceback模块

使用traceback模块打印异常信息

1
2
3
4
5
6
import traceback
try:
print('-------------')
num = 10 / 0
except:
traceback.print_exc()

5、Pycharm程序调试

断点调试

八、类和对象

python中一切皆对象

1、创建类

语法:

1
2
class 类名
内容

类名规范:由一个或多个单词组成,每个单词的首字母大写

案例

1
2
3
4
5
6
7
8
class Student:
pass


# python中一切皆对象,内存有开空间吗?
print(id(Student)) # 输出为 1541726811616
print(type(Student)) # 输出为 <class 'type'>
print(Student) # 输出为 <class '__main__.Student'>
  • 类的组成
    • 类属性
    • 初始化方法
    • 实例方法
    • 静态方法
    • 类方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Student:
# 类属性:类里面的变量
native_place = '福建'

# 初始化方法
def __init__(self, name):
# self.name称为实体属性,将局部变量赋值name给实体属性name
self.name = name

# 实例方法
def instanceFun(self):
print('我是一个实例方法')

# 静态方法
@staticmethod
def staticFun():
print('我是一个静态方法')

# 类方法
@classmethod
def classFun(cls):
print('我是一个类方法')

ps: self代表实例对象本身

2、创建对象

又称为类的实例化

语法:

1
实例名 = 类名()

举例:(使用上面的Student类)

1
2
3
4
5
6
7
8
9
ggw = Student('ggw')
print('---------| ggw |-----------')
print(id(ggw)) # 输出为 2602738007632
print(type(ggw)) # 输出为 <class '__main__.Student'>
print(ggw) # 输出为 <__main__.Student object at 0x0000025DFF463E50>
print('---------| Student |-----------')
print(id(Student)) # 输出为 1757065559632
print(type(Student)) # 输出为 <class 'type'>
print(Student) # 输出为 <class '__main__.Student'>

输出为

3、类属性、类方法、静态方法的使用方法

(1)类属性

类中方法外的变量称为类变量,被该类的所有对象共享(类指针)

举例:(使用上面的Student类)

1
2
3
4
5
6
7
stu1 = Student('ggw')
stu2 = Student('xpl')
print(Student.native_place) # 福建
print(stu1.name, stu2.name) # ggw xpl
print(stu1.native_place, stu2.native_place) # 福建 福建
Student.native_place = '吉林'
print(stu1.native_place, stu2.native_place) # 吉林 吉林

(2)类方法

使用@classmethod修饰的方法,使用类名直接访问的方法

1
2
3
stu = Student('ggw')
stu.classFun() # 输出为 我是一个类方法
Student.classFun() # 输出为 我是一个类方法

(3)静态方法

使用@staticmethod修饰的方法,使用类名直接访问的方法

1
2
3
stu = Student('ggw')
stu.staticFun() # 输出为 我是一个静态方法
Student.staticFun() # 输出为 我是一个静态方法

(4)实例方法

使用1:

1
实例名.实例方法名()

使用2:

1
类名.实例方法名(实例名)

案例

1
2
3
stu = Student('ggw')
stu.instanceFun() # 输出为 我是一个实例方法
Student.instanceFun(stu) # 输出为 我是一个实例方法

4、动态绑定属性和方法

python是动态语言,在创建对象后,可以动态地绑定属性和方法

  • 动态绑定属性

语法:

1
实例名.要绑定地属性名 = 值

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student:
def __init__(self, name):
self.name = name

def eat(self):
print(self.name + '在吃饭')


stu1 = Student('ggw')
stu2 = Student('xpl')
stu1.eat() # 输出为 ggw在吃饭
stu2.eat() # 输出为 xpl在吃饭
# 动态绑定 属性 gender
stu1.gender = '男'
print(stu1.name, stu1.gender) # 输出为 ggw 男
# print(stu2.name, stu2.gender) # 报错:AttributeError: 'Student' object has no attribute 'gender'

内存图

  • 动态绑定方法

语法:

1
实例名.要绑定地方法名 = 方法

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Student:
def __init__(self, name):
self.name = name

def eat(self):
print(self.name + '在吃饭')

def show():
print('我是新绑定的')


stu1 = Student('ggw')
stu2 = Student('xpl')
# 动态绑定 方法 myShow
stu2.myShow = show
stu2.myShow() # 我是新绑定的
# stu1.myShow() # 报错:AttributeError: 'Student' object has no attribute 'myShow'

内存图类似上面的

5、面向对象的三大特征

  • 封装: 提高程序的安全性
    • 将数据 (属性)和行为(法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样就无需关心方法内部的具体实现细节,从而隔离了复这样杂度。
    • 在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个_
  • 继承: 提高代码的复用性
  • 多态: 提高代码的可扩展性和可维护性

(1)封装的实现

如果该属性不希望在类对象外部被访问,前边使用两个_

举例:

1
2
3
4
5
6
7
8
9
10
11
12
class Student:
def __init__(self, name):
self.__name = name

def getName(self):
# return self.name # 报错:AttributeError: 'Student' object has no attribute 'name'
return self.__name


stu = Student('ggw')
print(stu.getName()) # 输出为ggw
# print(stu.__name) # 报错:AttributeError: 'Student' object has no attribute '_ _name'

扩展:就是要访问__name属性

1、dir(实例名)

1
print(dir(stu))

2、找到属性并访问

1
print(stu._Student__name)	# 输出为 ggw

所以可以访问,但是不要访问就好了

(2)继承的实现

语法:

1
2
class 子类类名(父类1, 父类2...):
内容
  • 如果一个类没有继承任何类,则默认继承object
  • Python支持多继承
  • 定义子类时,必须在其构造函数中调用父类的构造函数

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Person(object):   # 继承了object
def __init__(self, name, age):
self.__name = name
self.__age = age

def info(self):
print(self.__name, self.__age)

# 定义子类
class Student(Person):
def __init__(self, name, age, stu_number):
super().__init__(name, age)
self.__stu_number = stu_number

def getStuNumber(self):
print(self.__stu_number)

# 定义子类
class Teacher(Person):
def __init__(self, name, age, school):
super().__init__(name, age)
self.__school = school

def getSchool(self):
print(self.__school)


student = Student('张三', 18, '114514')
teacher = Teacher('罗翔', 38, 'xxx')
student.info() # 输出为 张三 18
student.getStuNumber() # 输出为 114514
teacher.info() # 输出为 罗翔 38
teacher.getSchool() # 输出为 xxx

使用 super() 函数来调用父类

多继承以后再看吧。。。

方法重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Person(object):  # 继承了object
def __init__(self, name, age):
self.__name = name
self.__age = age

def getName(self):
return self.__name

def getAge(self):
return self.__age

def info(self):
print(self.__name, self.__age)


# 定义子类
class Student(Person):
def __init__(self, name, age, stu_number):
super().__init__(name, age)
self.__stu_number = stu_number

def info(self):
print(super().getName(), super().getAge(), self.__stu_number)


# 定义子类
class Teacher(Person):
def __init__(self, name, age, school):
super().__init__(name, age)
self.__school = school

def info(self):
print(super().getName(), super().getAge(), self.__school)


student = Student('张三', 18, '114514')
teacher = Teacher('罗翔', 38, 'xxx')
student.info() # 输出为 张三 18 114514
teacher.info() # 输出为 罗翔 38 xxx

(3)多态的实现

简单地说,多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Animal(object):
def eat(self):
print('动物吃食物')

class Cat(Animal):
def eat(self):
print('猫吃鱼')

class Dog(Animal):
def eat(self):
print('狗吃骨头')

class Person(object):
def eat(self):
print('人吃粮食')


Animal().eat() # 输出为 动物吃食物
Cat().eat() # 输出为 猫吃鱼
Dog().eat() # 输出为 狗吃骨头
Person().eat() # 输出为 人吃粮食

静态语言与动态语言

  • 静态语言(JAVA)和动态语言关于多态的区别静态语言实现多态的三个必要条件
    • 继承
    • 方法重写
    • 父类引用指向子类对象9
  • 动态语言的多态崇尚“鸭子类型”当看到一只鸟走起来像鸭子、游泳起来像鸭子收起来也像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为。

6、object类

  • object类是所有类的父类,因此所有类都有object类的属性和方法
  • 内置函数 dir() 可以查看指定对象所属性
  • Object有一个 __str__() 方法,用于返回一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对 __str__() 进行重写

案例:

1
2
3
4
5
6
7
8
9
10
11
class Stusent:
def __init__(self, name):
self.__name = name

def __str__(self):
return f'我的名字是{self.__name}'


stu = Stusent('ggw')
print(dir(stu))
print(stu) # 会默认调用__str__()

输出为:

1
2
['_Stusent__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
我的名字是ggw

7、特殊的属性和方法

属性/方法 名称 描述
特殊属性 __dict__ 获得类对象或实例对象所绑定的属性和方法的字典
特殊方法 __len__() 通过重写__len__(),让内置函数len()的参数可以是自定义类型
特殊方法 __add__() 通过重写__add__(),可是自定义对象具有”+“功能
特殊方法 __new__() 用于创建对象
特殊方法 __init__() 对创建的对象进行初始化

特殊属性

  • __dict__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A:
pass

class B:
pass

class C(A, B):
def __init__(self, name, age):
self.__name = name
self.__age = age


instance = C('xxx', 20)
print(instance.__dict__)
print(C.__dict__)
print(instance.__class__) # 输出对象所属的类
print(C.__bases__) # 输出的是父类
print(C.__mro__) # 类的层次结构
print(A.__subclasses__()) # 输出子类列表

输出为

1
2
3
4
5
6
{'_C__name': 'xxx', '_C__age': 20}
{'__module__': '__main__', '__init__': <function C.__init__ at 0x000001E0977ECAF0>, '__doc__': None}
<class '__main__.C'>
(<class '__main__.A'>, <class '__main__.B'>)
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
[<class '__main__.C'>]

特殊方法

  • __add__()

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a = 100
b = 200
c = a + b
d = a.__add__(b)
print(c, d) # 输出为 300 300

class Student:
def __init__(self, name):
self.__name = name

def __add__(self, other):
return self.__name + other.__name


stu1 = Student('ggw')
stu2 = Student('xpl')
print(stu1 + stu2) # 输出为 ggwxpl
  • __len__()

案例

1
2
3
4
5
6
7
8
9
class A:
def __len__(self):
return '这是长度'


lst = [i for i in range(10, 50, 10)]
print(len(lst)) # 输出为 4
print(lst.__len__()) # 输出为 4
print(A().__len__()) # 输出为 这是长度
  • __new__()__init__()

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person(object):
def __new__(cls, *args, **kwargs):
print(f'__new__()执行了, cls的值的id为{id(cls)}')
obj = super().__new__(cls)
print(f'创建的对象id为{id(obj)}')
return obj

def __init__(self, name, age):
print(f'__init__()执行了, self的id为{id(self)}')
self.__name = name
self.__age = age


print(f'object这个类对象的id为{id(object)}')
print(f'Person这个类对象的id为{id(Person)}')
p1 = Person('张三', 20)
print(f'p1这个Person类的实例对象id为{id(p1)}')

输出为

1
2
3
4
5
6
object这个类对象的id为140718335637376
Person这个类对象的id为2753193282256
__new__()执行了, cls的值的id为2753193282256
创建的对象id为2753194573392
__init__()执行了, self的id为2753194573392
p1这个Person类的实例对象id为2753194573392

原理图

8、类的浅拷贝与深拷贝

  • 变量的赋值操作

    只是形成两个变量,实际上指向同一个对象

    案例

    1
    2
    3
    4
    5
    6
    7
    8
    class A:
    pass


    a1 = A()
    a2 = a1
    print(id(a1)) # 输出为 2143666190896
    print(id(a2)) # 输出为 2143666190896

    内存图

  • 浅拷贝

    python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象和拷贝对象会引用同一对象

    案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class CPU:
    pass

    class Disk:
    pass

    class Cumputer:
    def __init__(self, cpu, disk):
    self.cpu = cpu
    self.disk = disk


    cpu = CPU()
    disk = Disk()
    computer1 = Cumputer(cpu, disk)
    # 浅拷贝
    import copy
    computer2 = copy.copy(computer1)
    print(id(computer1), id(computer1.cpu), id(computer1.disk))
    print(id(computer2), id(computer2.cpu), id(computer2.disk))

    输出为

    1
    2
    1819258797744 1819258798032 1819258797792
    1819258797552 1819258798032 1819258797792

    内存图

  • 深拷贝

    使用copy模块的 deepcopy() 函数,递归拷贝对象中包含的子对象、源对象和拷贝对象所有的子对象各不相同

    案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class CPU:
    pass

    class Disk:
    pass

    class Cumputer:
    def __init__(self, cpu, disk):
    self.cpu = cpu
    self.disk = disk


    cpu = CPU()
    disk = Disk()
    computer1 = Cumputer(cpu, disk)
    # 深拷贝
    import copy
    computer2 = copy.deepcopy(computer1)
    print(id(computer1), id(computer1.cpu), id(computer1.disk))
    print(id(computer2), id(computer2.cpu), id(computer2.disk))

    输出为

    1
    2
    1859713646256 1859713646544 1859713646304
    1859713645920 1859713644480 1859713864400

    内存图

九、模块、包

1、什么是模块、模块化编程的好处

  • 模块英文为Modules
  • 函数与模块的关系
    • 一个模块中可以包含N多个函数(也可以N个类)
  • 在Python中一个扩展名为 .py 的文件就是一个模块
  • 使用模块的好处
    • 方便其它程序和脚本的导入并使用
    • 避免函数名和变量名冲突
    • 提高代码的可维护性
    • 提高代码的可重用性

2、导入模块

  • 创建模块

    • 新建一个 .py 文件,名称尽量不要与Python自带的标准模块名称相同
  • 导入模块

    • 只能导入包名和模块名

      1
      import 模块名称 [as别名]
    • 可以导入包、模块、函数、变量、类
      可以减少查询时间,提高访问速度

      1
      from 模块名称 import 函数/变量/类
    • 可以不用加模块名做前缀,简单但是一般不推荐

      1
      from 模块名称 import *

案例

1
2
3
4
5
6
7
8
9
import math
print(id(math)) # 输出为 2584154507360
print(type(math)) # 输出为 <class 'module'>
print(math) # 输出为 <module 'math' (built-in)>
print(math.pi) # 输出为 3.141592653589793


from math import pi
print(pi) # 输出为 3.141592653589793

导入自定义模块

calc.py文件内容

1
2
3
4
5
6
7
8
9
# 创建时间:2023-01-15 1:03
def mult(a, b):
print('计算结果为:', a * b)

def div(a, b):
try:
print('计算结果为:', a / b)
except ZeroDivisionError:
print('除数不能为0')

导入使用

1
2
3
import calc
calc.mult(10, 20) # 输出为 计算结果为: 200
calc.div(1, 0) # 输出为 除数不能为0

文件命名不规范的这样导入(没有.py)

1
MyKnn = __import__('04-MyKnn')

3、以主程序方式运行

在每个模块的定义中都包括一个记录模块名称的变量__name__,程序可以检查该变量,以确定他们在哪个模块中执行。如果一个模块不是被导入到其它程序中执行,那么它可能在解释器的顶级模块中执行。顶级模块的__name__变量的值为__main___

1
2
if __name__ == '__main__':
pass
1
2
3
4
5
6
""" 只有当点击本程序运行时,才执行运算 """
def add(a, b):
return a + b

if __name__ == '__main__':
print(add(10, 20))

如果没有这么处理

calc.py内容

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建时间:2023-01-15 1:03
def mult(a, b):
print('计算结果为:', a * b)

def div(a, b):
try:
print('计算结果为:', a / b)
except ZeroDivisionError:
print('除数不能为0')



print('我是calc')

运行的内容

1
2
3
import calc
calc.mult(100, 200)
calc.div(100, 10)

输出结果:

1
2
3
我是calc
计算结果为: 20000
计算结果为: 10.0

4、包

  • 包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下

  • 作用:

    • 代码规范
    • 避免模块名称冲突
  • 包与目录的区别

    • 包含_init__.py文件的目录称为包_,告诉python将该目录作为一个包来处理
    • 目录里通常不包含_init__.py文件

  • 包的导入

    1
    import 包名.模块名

    案例

    文件结构

    1
    2
    3
    4
    5
    ├───helloworld.py
    ├───directory
    └───package
    calc.py
    __init__.py

    导入

    1
    2
    3
    4
    import package.calc

    package.calc.mult(100, 200) # 输出为 计算结果为: 20000输出为
    package.calc.div(100, 10) # 输出为 计算结果为: 10.0

5、Python中常用的内置模块

模块名 描述
sys 与Python解释器及其环境操作相关的标准库
time 提供与时间相关的各种函数的标准库
os 提供了访问操作系统服务功能的标准库
calendar 提供与日期相关的各种函数的标准库
urllib 用于读取来自网上(服务器)的数据标准库
json 用于使用JSON序列化和反序列化对象
re 用于在字符串中执行正则表达式匹配和替换
math 提供标准算术运算函数的标准库
decimal 用于进行精确控制运算精度、有效数位和四舍五入操作的十进制运算
logging 提供了灵活的记录事件、错误、警告和调试信息等目志信息的功能

6、第三方模块的安装及使用

  • 安装

    1
    pip install 模块名

    未报错,安装成功

  • 使用

    import 模块名

1
2
3
4
5
6
7
8
9
10
import schedule
import time

def job():
print('hello')

schedule.every(3).seconds.do(job)
while True:
schedule.run_pending()
time.sleep(1)

模块无法生效

Pycharm无法解析

解决:配置Python Interpreter(Python解释器)

文件 -> 设置 -> 项目xxx -> Python解释器:

7、搜索路径

Python模块的导入需要路径搜索的过程

搜索路径:

1
2
3
4
import sys
print(sys.path)
for item in sys.path:
print(item)

不在同一目录下,需要将包、模块所在的路径添加进去

1
2
import sys
sys.path.append("C:\\Users\\GGW_2021\\Desktop\\笔记\\python")

十、文件读写

1、文件读写原理

  • 文件读写俗称"IO操作"

  • 文件读写流程

2、文件的读写操作

  • 使用内置函数 open()

    语法格式

    案例

    1
    2
    3
    file = open('./data.txt', 'r', encoding='gbk')
    print(file.readlines()) # 输出为 我是一个文件
    file.close()

3、常用的文件打开模式

  • 文件的类型(按文件的组织形式,文件分为以下两大类)
    • 文本文件: 存储的是普通"字符"文本,默认为unicode字符集,可以使用记事本程序打开
    • 二进制文件:把数据内容用"字节"进行存储,无法用记事本打开,必须使用专用的软件打开,举例,mp3音频文件
打开方式 描述
r 以只读的模式打开文件,文件指针将会放在文件的开头
w 以只写的模式打开文件,如果文件不存在则创建,如果文件存在,则覆盖原有内容,文件指针在文件的开头
a 以追加的模式打开文件,如果文件不存在则创建,文件指针在文件开头;如果文件存在,则在文件末尾追加内容,文件指在原文件的末尾
b 以二进制的方式打开文件,不能单独使用,需要与其他模式一起使用,例如:rb、wb
+ 与读写的方式打开文件,不能单独使用,需要与其他模式一起使用,例如:a+

4、文件对象常用的方法

方法 说明
read([size]) 从文件中读取size个字节或字符的内容符号,若省略size,则从文件头读取到文件尾,即一次读取文件所有内容
readline() 从文本文件中读取一行内容
readlines() 把文本文件中的每一行作为一个字符串对象,并将这些对象放入列表返回
write(str) 将字符串str内容写入文件
writelines(s_list) 将字符串列表s_list写入文本文件,不添加换行符
seek(offset
[,whence])
把文件指针移动到新的位置,offset表示相对于whence的位置(单位是字节):
offset:为正,向结束方向移动;为负,向开始方向移动
whence:不同的值代表不同的含义:
 0:从文件头开始计算(默认值)
 1:从当前位置开始计算
 2:从文件尾开始计算
tell() 返回文件指针当前位置
flush() 把缓冲区的内容写入文件,但不关闭文件
close() 把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
file = open('./data.txt', 'r+', encoding='gbk')
# print(file.read()) # 全部读取
# print(file.read(2)) # 读取两个字符
# print(file.readline()) # 读取一行
# print(file.readlines()) # 读取多行,放回列表

# file.write('哈哈哈哈') # 写入
# lst = ['hello', 'world', 'python']
# file.writelines(lst)

# file.seek(2)
# print(file.tell())
# print(file.read())
# print(file.tell())
file.close()

5、with语句(上下文管理器)

with语句可以自动的管理上下文资源,无论什么原因跳出with块,都能保证文件的正确关闭以此来达到释放资源的目的

语法

案例

1
2
with open('./data.txt', 'r+') as file:
print(file.read())

上下文管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
'''
MyContentMgr实现了特俗方法__enter__(), __exit__()
所以称该类的实例对象遵守了上下文管理器协议
该类的实例对象为上下文管理器
'''
class MyContentMgr:
def __enter__(self):
print('__enter__()执行了')
return self

def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__()执行了')

def show(self):
print('show()执行了')


with MyContentMgr() as file:
file.show()

'''输出为:
__enter__()执行了
show()执行了
__exit__()执行了
'''

6、os模块

  • os模块是Python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样。
  • os模块与os.path模块用于对目录或文件进行操作

案例

1
2
3
4
5
import os
# os.system('notepad.exe') # 打开记事本
# os.system('calc.exe') # 打开计算器
# 打开可执行文件
os.startfile('D:\\Tencent Files\\Bin\\QQ.exe') # 打开QQ

os模块操作目录的相关函数

函数 说明
getcwd() 返回当前工作目录
listdir(path) 返回指定路径下的文件和目录
mkdir(path[, mode]) 创建目录
makedirs(path1/path2…[, mode]) 创建多级目录
rmdir(path) 删除目录
removedirs(path1/path2…) 删除多级目录
chdir(path) 将path设置为当前工作目录
walk(path) 返回指定路径下的文件和目录,以及子目录下的文件和目录
(8、案例中有专门的例子)

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import os
# print(os.getcwd()) # 输出为 D:\python\project\demo

# print(os.listdir('./'))

# os.mkdir('./目录1') # 创建了目录1

# os.makedirs('./1/2') # 创建了多级目录

# os.rmdir('./目录1') # 删除了目录1

# os.removedirs('./1/2') # 删除了多级目录

os.chdir('D:\\') # 修改了当前工作目录
print(os.getcwd()) # 输出为 D:\

7、os.path模块

相关函数

函数 说明
abspath(path) 用于获取文件或目录的绝对路径
exists(path) 用于判断文件或目录是否存在,如果存在,返回True,否则返回False
join(path, name) 将目录与目录或者文件名拼接起来
split(path)
splitext(path) 分离文件名和拓展名
basename(path) 从一个目录中提取文件名
dirname(path) 从一个路径中提取文件路径,不包括文件名
isdir(path) 用于判断是否是路径

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import os.path
print('------------------------------------------')
print(os.path.abspath('data.txt'))
print('------------------------------------------')
print(os.path.exists('data.txt'), os.path.exists('xxx.py'))
print('------------------------------------------')
print(os.path.join('D:\\python\\project\\demo', 'helloworld.py'))
print('------------------------------------------')
print(os.path.split('D:\\python\\project\\demo\\helloworld.py'))
print('------------------------------------------')
print(os.path.splitext('helloworld.py'))
print(os.path.splitext('D:\\python\\project\\demo\\helloworld.py'))
print('------------------------------------------')
print(os.path.basename('D:\\python\\project\\demo\\helloworld.py'))
print('------------------------------------------')
print(os.path.dirname('D:\\python\\project\\demo\\helloworld.py'))
print('------------------------------------------')
print(os.path.isdir('D:\\python\\project\\demo\\helloworld.py'))
print(os.path.isdir('D:\\python\\project\\demo'))
print('------------------------------------------')

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
------------------------------------------
D:\python\project\demo\data.txt
------------------------------------------
True False
------------------------------------------
D:\python\project\demo\helloworld.py
------------------------------------------
('D:\\python\\project\\demo', 'helloworld.py')
------------------------------------------
('helloworld', '.py')
('D:\\python\\project\\demo\\helloworld', '.py')
------------------------------------------
helloworld.py
------------------------------------------
D:\python\project\demo
------------------------------------------
False
True
------------------------------------------

8、案例

列出指定目录下的所有.py文件

1
2
3
4
5
6
7
import os
path = os.getcwd()
lst = os.listdir(path)
for filename in lst:
# endwith 是不是以什么结尾
if filename.endswith('.py'):
print(filename)

walk()的使用

1
2
3
4
5
6
7
8
9
10
11
12
import os
path = os.getcwd()
lst = os.walk(path)
for dirpath, dirname, filename in lst:
print(dirpath, '||', dirname, '||', filename)
for key in dirname:
print(os.path.join(dirpath, key))
print('-------------')
for key in filename:
print(os.path.join(dirpath, key))
print('========================================')
print('========================================')

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
D:\python\project\demo || ['.idea', 'directory', 'package', '__pycache__'] || ['data.txt', 'helloworld.py']
D:\python\project\demo\.idea
D:\python\project\demo\directory
D:\python\project\demo\package
D:\python\project\demo\__pycache__
-------------
D:\python\project\demo\data.txt
D:\python\project\demo\helloworld.py
========================================
========================================
D:\python\project\demo\.idea || ['inspectionProfiles'] || ['.gitignore', 'demo.iml', 'encodings.xml', 'misc.xml', 'modules.xml', 'workspace.xml']
D:\python\project\demo\.idea\inspectionProfiles
-------------
D:\python\project\demo\.idea\.gitignore
D:\python\project\demo\.idea\demo.iml
D:\python\project\demo\.idea\encodings.xml
D:\python\project\demo\.idea\misc.xml
D:\python\project\demo\.idea\modules.xml
D:\python\project\demo\.idea\workspace.xml
========================================
========================================
D:\python\project\demo\.idea\inspectionProfiles || [] || ['profiles_settings.xml', 'Project_Default.xml']
-------------
D:\python\project\demo\.idea\inspectionProfiles\profiles_settings.xml
D:\python\project\demo\.idea\inspectionProfiles\Project_Default.xml
========================================
========================================
D:\python\project\demo\directory || [] || []
-------------
========================================
========================================
D:\python\project\demo\package || ['__pycache__'] || ['calc.py', '__init__.py']
D:\python\project\demo\package\__pycache__
-------------
D:\python\project\demo\package\calc.py
D:\python\project\demo\package\__init__.py
========================================
========================================
D:\python\project\demo\package\__pycache__ || [] || ['calc.cpython-310.pyc', '__init__.cpython-310.pyc']
-------------
D:\python\project\demo\package\__pycache__\calc.cpython-310.pyc
D:\python\project\demo\package\__pycache__\__init__.cpython-310.pyc
========================================
========================================
D:\python\project\demo\__pycache__ || [] || []
-------------
========================================
========================================

十一、实操案例

1、向文件输出内容

1
2
3
4
5
6
7
''' 方法一 '''
file = open('C:\\Users\\GGW_2021\\Desktop\\笔记\\python\\text.txt', 'w')
print('hello world', file=file)
file.close()
''' 方法二 '''
with open('C:\\Users\\GGW_2021\\Desktop\\笔记\\python\\text.txt', 'w') as file:
file.write('hello world!!')

2、模拟高铁售票系统

安装模块

1
pip install prettytable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import prettytable as pt


def showTable(rowNum):
table = pt.PrettyTable() # 创建对象
table.field_names = ['行号', '座位1', '座位2', '座位3', '座位4', '座位5'] # 设定表头
for i in range(rowNum):
lst = [f'第{i + 1}行', '有票', '有票', '有票', '有票', '有票']
table.add_row(lst)
print(table)


if __name__ == '__main__':
showTable(3)

输出结果

1
2
3
4
5
6
7
+-------+-------+-------+-------+-------+-------+
| 行号 | 座位1 | 座位2 | 座位3 | 座位4 | 座位5 |
+-------+-------+-------+-------+-------+-------+
| 第1行 | 有票 | 有票 | 有票 | 有票 | 有票 |
| 第2行 | 有票 | 有票 | 有票 | 有票 | 有票 |
| 第3行 | 有票 | 有票 | 有票 | 有票 | 有票 |
+-------+-------+-------+-------+-------+-------+

3、创建虚拟环境

  • 创建虚拟环境
1
python -m venv [虚拟环境名]

运行:

进去scripts文件夹,执行active.bat


  • 转移环境
1
pip freeze > requirement.txt 

接受

1
pip install -r requirement.txt