绪论
个人学习笔记,并且主要针对机器学习深度学习,可能会有增删改,不涉及其他python方向,仅供参考。 [官方文档最靠谱](3.12.0 Documentation (python.org))
第二章 基本语法元素
第一部分 数据类型
1. 基本类型:数字、字符串、布尔
1.1 数字类型
- int 整型 整数
2
2
- float 浮点型 带小数的数
2.0
- complex 复数 a+bj
3+4j
1.2 字符串类型
- str 字符串 视作文本
- 组成: 由数字、字母、空格、其他字符等组合而成
- 表达: 用" " 或' '
"python 123 @#$^&(())"
'python 123 @#$^&(())'
1.3 布尔类型
- bool 布尔类型
- 主要用于逻辑运算
y = 2 < 1
y
False
上述类型均可定义单个数据,如果我们有一组数据,该如何表示?
2. 组合类型:列表、元组、字典、集合
2.1 列表
- list 列表 序列类型: 数据有位置顺序
- 表示方式: [data1,data2....]
a = [1, 2, 3, 4, 5]
a[0]
1
2.2 元组
- tuple 元组 序列类型
- 表示方式: (data1,data2...)
- 元素不支持修改——“不可变的列表”
b = (1, 2, 3, 4, 5)
b[0]
1
2.3 字典
- dict 字典 映射类型: 通过“键”-“值”的映射实现数据存储和查找
- 表示方式: {key1:value1 , key2:value2 , ...}
student = {201901: "小明", 201902: "小红", 201903: "小强"}
student[201901]
'小明'
2.4 集合
- set 集合 一系列互不相等元素的集合,无序的
- 表示方式: {data1,data2...}
s = {"小明", "小红", "小强", "小明"}
s
{'小强', '小明', '小红'}
在程序中,我们如何来引用这些数据?
- 非常通俗的处理办法:赋值给一个变量
第二部分 变量
1. 变量的概念
- “量” 实实在在的对象:如数据、抽象
- “变” 可变性:增、删、查、改等
- 变量定义二要素: 变量名、赋值
x = 1
2. 变量的命名
2.1 哪些可以用来做变量名?
- 大写字母、小写字母、数字、下划线、汉字及其组合。
- 严格区分大小写
Python_is_第1名 = True
python_is_第1名 = False
2.2 哪些情况不被允许?
- 首字符不允许为数字
1_fruit = "apple"
File "<ipython-input-59-e3b1d93d01a0>", line 1
1_fruit = "apple"
^
SyntaxError: invalid token
- 变量名中间不能有空格
my fruit = "apple"
File "<ipython-input-60-36327c3a601f>", line 1
my fruit = "apple"
^
SyntaxError: invalid syntax
- 不能与33个Pyhton保留字相同
if = True
File "<ipython-input-62-4c75bcfb9bb9>", line 1
if = True
^
SyntaxError: invalid syntax
2.3 变量名定义技巧
- 变量名尽可能有实际意义,表征数据的某种特性
a = [17, 18, 19]
age_of_students = [17, 18, 19]
- 下划线(推荐:变量和函数名) 变量名由多个单词组成:用_连接多个单词
- 驼峰体(推荐:类名) 变量名由多个单词组成:单词首字母大写
AgeOfStudents
- 尽量避免用中文和拼音做变量名
- 特殊的变量:常量(不变的量,如、e) 变量名所有字母均为大写
MAX_ITERATION = 1000
3. 变量的赋值
3.1 一般赋值
- 通过等号自右向左进行赋值
x = 1+2
x
3
3.2 增量赋值
x = 10
x = x+10
x
x += 10
20
3.3 打包赋值
x, y = 1, 2
print(x, y)
x, y = y, x
print(x, y)
1 2
2 1
第三部分 控制流程
1. 顺序流程
- 自上向下依次执行
【小例子】实现1到5的整数求和
# res = 1+2+3+4+5
res = 0 # 赋初值
res += 1
res += 2
res += 3
res += 4
res += 5
res # 显示结果
15
2. 循环流程——遍历循环(for)
主要形式:
- for 元素 in 可迭代对象:
执行语句
执行过程:
- 从可迭代对象中,依次取出每一个元素,并进行相应的操作
【小例子】实现1到5的整数求和
res = 0
for i in [1,2,3,4,5]: # 每次迭代,取出一个i
res += i # 对每次迭代取出的i 进行相应操作
res # 遍历结束后,执行后续语句
15
3. 循环流程——无限循环(while)
主要形式:
- while 判断条件:
- 条件为真,执行语句
- 条件为假,while 循环结束
【小例子】实现1到5的整数求和
i = 1
res = 0
while i <= 5: # 若i不大于5,则循环继续
res += i
i += 1
res # 若循环条件不成立,循环停止,执行后续语句
15
4. 分支流程(if)
最简单的形式:
- if 判断条件:
- 条件为真,执行语句
- else:
- 条件为假,执行语句
age = 18
if age > 22:
print("可以结婚啦")
else:
print("em,着急了点,再等等。。。")
em,着急了点,再等等。。。
- 有了数据和变量,以及控制流程这些个中间过程后
- 我们回过头来考虑下程序的输入和输出
第四部分 输入输出
1. 数据从哪里来?
1. 外部文件导入
- 从本地硬盘、网络端读入等
- 该部分内容放在 第八章《文件、异常和模块》进行讲解
2. 程序中定义
age = 18
name = "Tom"
3. 动态交互输入 input
- 在程序运行的过程中进行输入
x = input("请输入一个数字:")
x
请输入一个数字:4
'4'
y = input("请输入一个数字:")
y
请输入一个数字:3.5
'3.5'
x + y
'43.5'
type(x)
str
- eval() 去掉引号
x = eval(input("请输入一个数字:"))
x
请输入一个数字:4
4
y = eval(input("请输入一个数字:"))
y
请输入一个数字:3.5
3.5
x + y
7.5
2. 数据到哪里去?
1. 存储到本地硬盘或网络端
- 该部分内容放在 第八章《文件、异常和模块》进行讲解
2. 打印输出 print
- 直接打印数据
print("我是一颗小星星")
我是一颗小星星
print(1234)
1234
- 打印变量
x = 1024
print(x)
1024
- print 默认换行
print(1)
print(2)
1
2
- 如果不想换行怎么办?
- 换行控制 end=
print(123,end=" ")
print(456)
123 456
- 有时候,我们需要一些复杂的输出:比如几个变量一起组合输出
PI = 3.1415926
E = 2.71828
print("PI = ", PI, "E = ", E)
PI = 3.1415926 E = 2.71828
3. 格式化输出方法 format
- 基本格式:"字符{ 0 }字符{ 1 }字符".format(v0,v1)
print("PI = {0},E = {1}".format(PI, E))
PI = 3.1415926,E = 2.71828
print("PI = {1},E = {0}".format(PI, E))
PI = 2.71828,E = 3.1415926
print("PI = {},E = {}".format(PI, E))
PI = 3.1415926,E = 2.71828
print("PI = {0},E = {0}".format(PI, E))
PI = 3.1415926,E = 3.1415926
- 再进一步 修饰性输出
- 填充输出
# ____3.1415926_____ 进行填充
print("{0:_^20}".format(PI))
# 0代表PI 冒号代表修饰 _代表填充图案 ^ 表示居中 整体输出宽度为20
# <左对齐 >右对齐
_____3.1415926______
print("{0:*<30}".format(PI))
3.1415926*********************
2. 数字千分位分隔符
- 显示1,000,000
print("{0:,}".format(10000000))
10,000,000
print("{0:&>20,}".format(10000000))
# 填充符号写在前& 分割符号写在后,
&&&&&&&&&&10,000,000
print("{0:,&>20}".format(10000000))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-35-9f30412a92d9> in <module>
----> 1 print("{0:,&>20}".format(10000000))
ValueError: Invalid format specifier
3. 浮点数简化输出
- 留2位小数
print("{0:.2f}".format(PI))
3.14
- 按百分数输出
print("{0:.1%}".format(0.818727))
81.9%
- 科学计数法输出
print("{0:.2e}".format(0.818727))
8.19e-01
4. 整数的进制转换输出
- 十进制整数转二进制、unicode码、十进制、八进制、十六进制输出
"二进制{0:b},Unicode码{0:c},十进制{0:d},八进制{0:o},十六进制{0:x}".format(450)
'二进制111000010,Unicode码ǂ,十进制450,八进制702,十六进制1c2'
第五部分 程序格式
1. 行最大长度
所有行限制的最大字符数为79
2. 缩进
- 用缩进来表示语句间的逻辑
- 在 for while if def class等 :之后下一行开始进行缩进,表明后续代码与前句之间的从属关系
- 缩进量:4字符
for i in [1, 2, 3]:
print(i)
print("打印结束")
3. 使用空格
- 二元运算符两边加一个空格
x = 2 # 赋值
x + = 4 # 增量
6 > 2 # 比较
- 使用不同优先级的运算符,考虑在最低优先级的运算符周围添加空格
x = x*2 - 1
z = x*x + y*y
c = (a+b) * (a-b)
- 在逗号后使用空格
x, y = 1, 2
ls = [1, 2, 3]
- 不要使用一个以上的空格
x = 2 # 空格一个就够了,不应过多
4. 避免使用空格
- 在制定关键字参数或者默认参数值的时候,不要在=附近加上空格
def fun(n=1, m=2):
print(n, m)
小结
1、以上属于PEP8格式指南的部分内容,养成良好的编码规范利人利己
2、格式约定的目的:
- 使大量Python代码风格一致
- 提升代码可读性
3、尽信书不如无书,不应死板教条的执行格式规范
- 项目规范优先
5. 注释
- 单行注释
- 格式:# 注释内容
a=1 # 我是单行注释
- 多行注释
- 格式:"""注释内容,可分行"""
"""
妈妈
我
好像
发现了
写诗
的
诀窍
"""
第三章 基本数据类型
第一部分 数字类型
1.1 数字类型的组成
1.1.1 整数——不同进制的转换
- 默认输入十进制
- 二进制0b、八进制0o、十六进制0x
16 == 0b10000 == 0o20 == 0x10
True
- 十进制与其他进制的转换
a = bin(16) # 转二进制
b = oct(16) # 转八进制
c = hex(16) # 转十六进制
print(a, b, c)
0b10000 0o20 0x10
注意:上述转换后结果为字符串类型
a == b == c
False
type(a)
str
- 其他进制转十进制
d = int(a, 2) # 二进制转十进制
e = int(b, 8) # 八进制转十进制
f = int(c, 16) # 十六进制转十进制
print(d, e, f)
16 16 16
1.1.2 浮点数——不确定性
- 不确定小数问题
(0.1+0.2) == 0.3
False
0.1+0.2
0.30000000000000004
计算机采用二进制小数来表示浮点数的小数部分
-
部分小数不能用二进制小数完全表示
二进制 十进制
0.00011001100110011001 0.09999942779541016 0.0011001100110011 0.1999969482421875 0.01001100110011001 0.29999542236328125 0.01100110011001101 0.40000152587890625 0.1 0.5
- 通常情况下不会影响计算精度
0.1 + 0.7
0.7999999999999999
- 四舍五入获得精确解
a = 3*0.1
print(a)
0.30000000000000004
b = round(a, 1)
print(b)
b == 0.3
0.3
True
1.1.3 复数——a+bj
- 大写J或小写j均可
3+4j
2+5J
(2+5j)
- 虚部系数为1时,需要显式写出
2+1j
1.2 数字运算操作符(a 操作符 b)
- 加减乘除运算 + - / *
(1+3-4*2)/5
-0.8
- 取反 -
x = 1
-x
-1
- 乘方运算 **
2**3
8
- 整数商// 和 模运算%
13//5 # 整数商 x/y 向下取整数
2
13 % 5 # 模运算 余数 13=2*5+3
3
几点说明
- 整数与浮点数运算结果是浮点数
- 除法运算的结果是浮点数
1+1.5
2.5
2/5
0.4
8/4
2.0
1.3 数字运算操作函数 function(x, ...)
- 求绝对值 abs()
abs(-5)
5
abs(3+4j) # 对复数a+bj 执行的是求模运算(a^2+b^2)^0.5
5.0
- 幂次方 pow(x,n)
pow(2, 5) # pow(x,n) x的n次方 等价于x**n
32
pow(2, 5, 3) # 2^5 % 3 更快速
2
- 四舍五入 round(x,n)
a = 1.618
print(round(a)) # 默认四舍五入为整数
2
print(round(a, 2)) # 参数2表示四舍五入后保留2位小数
1.62
print(round(a, 5)) # 位数不足,无需补齐
1.618
- 整数商和模运算 divmod(x,y)
- 等价于返回二元元组(x//y,x % y)
divmod(13, 5) # 较(x//y,x % y)更快,只执行了一次x/y
(2, 3)
- 序列最大/最小值 max( ) min( )
max(3, 2, 3, 6, 9, 4, 5)
9
a = [3, 2, 3, 6, 9, 4, 5]
print("max:", max(a))
print("min:", min(a))
max: 9
min: 2
- 求和sum(x)
sum((1, 2, 3, 4, 5))
15
- 借助科学计算库 math\scipy\numpy
import math # 导入库
print(math.exp(1)) # 指数运算 e^x
print(math.log2(2)) # 对数运算
print(math.sqrt(4)) # 开平方运算 等价于4^0.5
2.718281828459045
1.0
2.0
import numpy as np
a = [1, 2, 3, 4, 5]
print(np.mean(a)) # 求均值
print(np.median(a)) # 求中位数
print(np.std(a)) # 求标准差
3.0
3.0
1.4142135623730951
第二部分 字符串类型
2.1 字符串的表达
- 用""或''括起来的任意字符
print("Python")
print('Python')
Python
Python
- 字符串中有双引号或单引号的情况
双中有单
print("I'm 18 years old")
I'm 18 years old
单中有双
print('"Python" is good')
"Python" is good
双中有双,单中有单——转义符 \
# print(""Python" is good")
print("\"Python\" is good") # \ 我是个字符呀
"Python" is good
转义符可以用来换行继续输入
# 等等,我还没完事!
s = "py\
thon"
print(s)
python
2.2 字符串的性质
2.2.1 字符串的索引
s = "My name is Peppa Pig"
变量名[位置编号]
- 正向索引——从零开始递增
- 位置编号不能超过字符串的长度
print(s[0])
print(s[2])
print(s[5])
M
m
s = "My name is Peppa Pig"
- 反向索引——从-1开始递减
print(s[-1])
print(s[-3])
print(s[-5])
g
P
a
索引只能获得一个字符,如何获得多个字符?
2.2.2 字符串的切片
变量名[开始位置:结束位置:切片间隔]
- 切片间隔如不设置默认为1,可省略
- 切片范围不包含结束位置
s = "Python"
print(s[0:3:1]) #间隔为1
Pyt
print(s[0:3])
Pyt
print(s[0:3:2]) #间隔为2
Pt
- 起始位置是0 可以省略
- 结束位置省略,代表可以取到最后一个字符
- 可以使用反向索引
s = "Python"
print(s[0:6])
Python
print(s[:6])
Python
print(s[:])
Python
print(s[-6:])
Python
反向切片
- 起始位置是-1也可以省略
- 结束位置省略,代表可以取到第一个字符
s = "123456789"
print(s[-1:-10:-1])
987654321
print(s[:-10:-1])
987654321
print(s[::-1])
987654321
2.3 字符串操作符
2.3.1 字符串的拼接
- 字符串1+字符串2
a = "I love "
b = "my wife "
a+b
'I love my wife '
2.3.2 字符串的成倍复制
- 字符串 * n n * 字符串
c = a+b
print(c*3)
print(3*c)
I love my wife I love my wife I love my wife
I love my wife I love my wife I love my wife
2.2.3 成员运算
- 子集in全集 任何一个连续的切片都是原字符串的子集
folk_singers = "Peter, Paul and Mary"
"Peter" in folk_singers
True
"PPM" in folk_singers
False
- 遍历字符串字符 for 字符 in 字符串
for s in "Python":
print(s)
P
y
t
h
o
n
2.4 字符串处理函数
2.4.1 字符串的长度
- 所含字符的个数
s = "python"
len(s)
6
2.4.2 字符编码
将中文字库,英文字母、数字、特殊字符等转化成计算机可识别的二进制数
- 每个单一字符对应一个唯一的互不重复的二进制编码
- Python 中使用的是Unicode编码
将字符转化为Unicode码——ord(字符)
print(ord("1"))
print(ord("a"))
print(ord("*"))
print(ord("中"))
print(ord("国"))
49
97
42
20013
22269
将Unicode码转化为字符——chr(Unicode码)
print(chr(1010))
print(chr(10000))
print(chr(12345))
print(chr(23456))
ϲ
✐
〹
宠
2.5 字符串的处理方法
2.5.1 字符串的分割——字符串.split(分割字符)
- 返回一个列表
- 原字符串不变
上述特性适合以下所有字符串处理方法
languages = "Python C C++ Java PHP R"
languages_list = languages.split(" ")
print(languages_list)
print(languages)
['Python', 'C', 'C++', 'Java', 'PHP', 'R']
Python C C++ Java PHP R
2.5.2 字符串的聚合——“聚合字符”.join(可迭代数据类型)
- 可迭代类型 如:字符串、列表
s = "12345"
s_join = ",".join(s)
s_join
'1,2,3,4,5'
- 序列类型的元素必须是字符类型
# s = [1, 2, 3, 4, 5]
s = ["1", "2", "3", "4", "5"]
"*".join(s)
'1*2*3*4*5'
3.5.3 删除两端特定字符——字符串.strip(删除字符)
- strip从两侧开始搜索,遇到指定字符执行删除,遇到非指定字符,搜索停止
- 类似的还有左删除lstrip和右删除rstrip
s = " I have many blanks "
print(s.strip(" ")) # 还有吗?hahaha
print(s.lstrip(" "))
print(s.rstrip(" "))
print(s)
I have many blanks
I have many blanks
I have many blanks
I have many blanks
3.5.4 字符串的替换——字符串.replace("被替换","替换成")
s = "Python is coming"
s1 = s.replace("Python","Py")
print(s1)
Py is coming
3.5.5 字符串统计——字符串.count("待统计字符串")
s = "Python is an excellent language"
print("an:", s.count("an"))
print("e:", s.count("e"))
an: 2
e: 4
3.3.6 字符串字母大小写
- 字符串.upper() 字母全部大写
s = "Python"
s.upper()
'PYTHON'
- 字符串.lower() 字母全部小写
print(s.lower())
print(s)
python
Python
- 字符串.title()首字母大写
s.title()
'Python'
第三部分 布尔类型 TRUE or False
3.1 逻辑运算的结果
a = 10
print(a > 8)
print(a == 12)
print(a < 5)
True
False
False
- any() all()
print(any([False,1,0,None])) # 0 False None 都是无
print(all([False,1,0,None]))
True
False
3.2 指示条件
n = 2800
while True:
m = eval(input("请输入一个正整数:"))
if m == n:
print("你猜对啦")
break
elif m > n:
print("太大了")
else:
print("太小了")
请输入一个正整数:28
太小了
请输入一个正整数:2800
你猜对啦
3.3 作为掩码
import numpy as np
x = np.array([[1, 3, 2, 5, 7]]) # 定义 numpy数组
print(x > 3)
x[x > 3]
[[False False False True True]]
array([5, 7])
第四部分 类型判别及类型转换
4.1 类型判别
- type(变量)
age = 20
name = "Ada"
print(type(age))
print(type(name))
<class 'int'>
<class 'str'>
- isinstance(变量,预判类型) 承认继承
- 变量类型是预判类型的子类型,则为真,否则为假
print(isinstance(age, int)) # 承认继承
True
print(isinstance(age, object))
print(isinstance(name, object)) # object 是老祖宗
True
True
- 字符串检查方法
字符串.isdigit()字符是否只有数字组成
age = "20"
name = "Ada"
age.isdigit()
True
name.isdigit()
False
字符串.isalpha()字符是否只有字母组成
name.isalpha()
True
age.isalpha()
False
字符串.isalnum()字符是否只有数字和字母组成
"Ada20".isalnum() # 比如可用于判断用户名是否合法
True
4.2 类型转换
- 数字类型转字符串 str(数字类型)
age = 20
print("My age is "+str(age))
My age is 20
- 仅有数字组成的字符串转数字 int() float() eval()
s1 = "20"
s2 = "10.1"
int(s1) # 仅整型
# int(s2)
20
float(s1)
20.0
float(s2)
10.1
eval(s1) #只去掉引号
20
eval(s2)
10.1
第四章 组合数据类型
4.1 列表
4.1.1 列表的表达
- 序列类型:内部元素有位置关系,能通过位置序号访问其中元素
- 列表是一个可以使用多种类型元素,支持元素的增、删、查、改操作的序列类型
ls = ["Python", 1989, True, {"version": 3.7}]
ls
['Python', 1989, True, {'version': 3.7}]
- 另一种产生方式:list(可迭代对象)
- 可迭代对象包括:字符串、元组、集合、range()等
字符串转列表
list("人工智能是未来的趋势")
['人', '工', '智', '能', '是', '未', '来', '的', '趋', '势']
元组转列表
list(("我", "们", "很", "像"))
['我', '们', '很', '像']
集合转列表
list({"李雷", "韩梅梅", "Jim", "Green"})
['Green', 'Jim', '李雷', '韩梅梅']
特殊的range()
for i in [0, 1, 2, 3, 4, 5]:
print(i)
0
1
2
3
4
5
for i in range(6):
print(i)
0
1
2
3
4
5
- range(起始数字,中止数字,数字间隔)
如果起始数字缺省,默认为0
必须包含中止数字
数字间隔缺省,默认为1
for i in range(1, 11, 2):
print(i)
1
3
5
7
9
- range()转列表
list(range(1, 11, 2))
[1, 3, 5, 7, 9]
4.1.2 列表的性质
- 列表的长度——len(列表)
ls = [1, 2, 3, 4, 5]
len(ls)
5
- 列表的索引——与同为序列类型的字符串完全相同
变量名[位置编号]
正向索引从0开始
反向索引从-1开始
cars = ["BYD", "BMW", "AUDI", "TOYOTA"]
print(cars[0])
print(cars[-1])
BYD
TOYOTA
- 列表的切片
变量名[开始位置:结束位置:切片间隔]
cars = ["BYD", "BMW", "AUDI", "TOYOTA"]
- 正向切片
print(cars[:3]) # 前三个元素,开始位置缺省,默认为0;切片间隔缺省,默认为1
['BYD', 'BMW', 'AUDI']
print(cars[1:4:2]) # 第二个到第四个元素 前后索引差为2
['BMW', 'TOYOTA']
print(cars[:]) # 获取整个列表,结束位置缺省,默认取值到最后
['BYD', 'BMW', 'AUDI', 'TOYOTA']
print(cars[-4:-2]) # 获取前两个元素
['BYD', 'BMW']
- 反向切片
cars = ["BYD", "BMW", "AUDI", "TOYOTA"]
print(cars[:-4:-1]) # 开始位置缺省,默认为-1
print(cars[::-1]) # 获得反向列表
['TOYOTA', 'AUDI', 'BMW']
['TOYOTA', 'AUDI', 'BMW', 'BYD']
4.1.3 列表的操作符
- 用** list1+lis2 **的形式实现列表的拼接
a = [1, 2]
b = [3, 4]
a+b # 该用法用的不多
[1, 2, 3, 4]
- 用 n*list 或 list*n 实现列表的成倍复制
初始化列表的一种方式
[0]*10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4.1.4 列表的操作方法
1、增加元素
- 在末尾增加元素——列表.append(待增元素)
languages = ["Python", "C++", "R"]
languages.append("Java")
languages
['Python', 'C++', 'R', 'Java']
- 在任意位置插入元素——列表.insert(位置编号,待增元素)
在位置编号相应元素前插入待增元素
languages.insert(1, "C")
languages
['Python', 'C', 'C++', 'R', 'Java']
- 在末尾整体并入另一列表——列表1.extend(列表2)
append 将列表2整体作为一个元素添加到列表1中
languages.append(["Ruby", "PHP"])
languages
['Python', 'C', 'C++', 'R', 'Java', ['Ruby', 'PHP']]
extend 将待列表2内的元素逐个添加到列表1中
languages = ['Python', 'C', 'C++', 'R', 'Java']
languages.extend(["Ruby", "PHP"])
languages
['Python', 'C', 'C++', 'R', 'Java', 'Ruby', 'PHP']
2、删除元素
- 删除列表i位置的元素 列表.pop(位置)
languages = ['Python', 'C', 'C++', 'R', 'Java']
languages.pop(1)
languages
['Python', 'C++', 'R', 'Java']
- 不写位置信息,默认删除最后一个元素
languages.pop()
languages
['Python', 'C++', 'R']
- 删除列表中的第一次出现的待删元素 列表.remove(待删元素)
languages = ['Python', 'C', 'R', 'C', 'Java']
languages.remove("C")
languages
['Python', 'R', 'C', 'Java']
languages = ['Python', 'C', 'R', 'C', 'Java']
while "C" in languages:
languages.remove("C")
languages
['Python', 'R', 'Java']
3、查找元素
- 列表中第一次出现待查元素的位置 列表.index(待查元素)
languages = ['Python', 'C', 'R','Java']
idx = languages.index("R")
idx
2
4、修改元素
- 通过"先索引后赋值"的方式,对元素进行修改 列表名[位置]=新值
languages = ['Python', 'C', 'R','Java']
languages[1] = "C++"
languages
['Python', 'C++', 'R', 'Java']
5、列表的复制
- 错误的方式
languages = ['Python', 'C', 'R','Java']
languages_2 = languages
print(languages_2)
['Python', 'C', 'R', 'Java']
languages.pop()
print(languages)
print(languages_2)
['Python', 'C', 'R']
['Python', 'C', 'R']
-
正确的方式——浅拷贝
-
方法1:列表.copy()
languages = ['Python', 'C', 'R','Java']
languages_2 = languages.copy()
languages.pop()
print(languages)
print(languages_2)
['Python', 'C', 'R']
['Python', 'C', 'R', 'Java']
- 方法2:列表[ : ]
languages = ['Python', 'C', 'R','Java']
languages_3 = languages[:]
languages.pop()
print(languages)
print(languages_3)
['Python', 'C', 'R']
['Python', 'C', 'R', 'Java']
6、列表的排序
- 使用列表.sort()对列表进行永久排序
- 直接在列表上进行操作,无返回值
ls = [2, 5, 2, 8, 19, 3, 7]
ls.sort()
ls
[2, 2, 3, 5, 7, 8, 19]
- 递减排列
ls.sort(reverse = True)
ls
[19, 8, 7, 5, 3, 2, 2]
- 使用sorted(列表)对列表进行临时排序
- 原列表保持不变,返回排序后的列表
ls = [2, 5, 2, 8, 19, 3, 7]
ls_2 = sorted(ls)
print(ls)
print(ls_2)
[2, 5, 2, 8, 19, 3, 7]
[19, 8, 7, 5, 3, 2, 2]
sorted(ls, reverse = True)
[19, 8, 7, 5, 3, 2, 2]
7、列表的翻转
- 使用列表.reverse()对列表进行永久翻转
- 直接在列表上进行操作,无返回值
ls = [1, 2, 3, 4, 5]
print(ls[::-1])
ls
[5, 4, 3, 2, 1]
[1, 2, 3, 4, 5]
ls.reverse()
ls
[5, 4, 3, 2, 1]
8、使用for循环对列表进行遍历
ls = [1, 2, 3, 4, 5]
for i in ls:
print(i)
1
2
3
4
5
4.2 元组
4.2.1 元组的表达
- 元组是一个可以使用多种类型元素,一旦定义,内部元素不支持增、删和修改操作的序列类型
通俗的讲,可以将元组视作“不可变的列表”
names = ("Peter", "Pual", "Mary")
4.2.2 元组的操作
- 不支持元素增加、元素删除、元素修改操作
- 其他操作与列表的操作完全一致
4.2.3 元组的常见用处
打包与解包
- 例1
def f1(x): # 返回x的平方和立方
return x**2, x**3 # 实现打包返回
print(f1(3))
print(type(f1(3))) # 元组类型
(9, 27)
<class 'tuple'>
a, b = f1(3) # 实现解包赋值
print(a)
print(b)
9
27
- 例2
numbers = [201901, 201902, 201903]
name = ["小明", "小红", "小强"]
list(zip(numbers,name))
[(201901, '小明'), (201902, '小红'), (201903, '小强')]
for number,name in zip(numbers,name): # 每次取到一个元组,立刻进行解包赋值
print(number, name)
201901 小明
201902 小红
201903 小强
4.3 字典
4.3.1 字典的表达
- 映射类型: 通过“键”-“值”的映射实现数据存储和查找
- 常规的字典是无序的
students = {201901: '小明', 201902: '小红', 201903: '小强'}
students
字典键的要求
- 1、字典的键不能重复
students = {201901: '小明', 201901: '小红', 201903: '小强'}
students
{201901: '小红', 201903: '小强'}
-
2、字典的键必须是不可变类型,如果键可变,就找不到对应存储的值了
-
不可变类型:数字、字符串、元组。 一旦确定,它自己就是它自己,变了就不是它了。
-
可变类型:列表、字典、集合。 一旦确定,还可以随意增删改。
d1 = {1: 3}
d2 = {"s": 3}
d3 = {(1,2,3): 3}
d = {[1, 2]: 3}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-68-bf7f06622b3f> in <module>
----> 1 d = {[1, 2]: 3}
TypeError: unhashable type: 'list'
d = {{1:2}: 3}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-69-188e5512b5fe> in <module>
----> 1 d = {{1:2}: 3}
TypeError: unhashable type: 'dict'
d = {{1, 2}: 3}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-70-c2dfafc1018a> in <module>
----> 1 d = {{1, 2}: 3}
TypeError: unhashable type: 'set'
4.3.2 字典的性质
- 字典的长度——键值对的个数
students = {201901: '小明', 201902: '小红', 201903: '小强'}
len(students)
3
- 字典的索引
通过 字典[键] 的形式来获取对应的值
students = {201901: '小明', 201902: '小红', 201903: '小强'}
students[201902]
'小红'
4.3.3 字典的操作方法
1、增加键值对
- 变量名[新键] = 新值
students = {201901: '小明', 201902: '小红', 201903: '小强'}
students[201904] = "小雪"
students
{201901: '小明', 201902: '小红', 201903: '小强', 201904: '小雪'}
2、删除键值对
- 通过del 变量名[待删除键]
students = {201901: '小明', 201902: '小红', 201903: '小强'}
del students[201903]
students
{201901: '小明', 201902: '小红'}
- 通过变量名.pop(待删除键)
students = {201901: '小明', 201902: '小红', 201903: '小强'}
value = students.pop(201903) # 删除键值对,同时获得删除键值对的值
print(value)
print(students)
小强
{201901: '小明', 201902: '小红'}
- 变量名.popitem() 随机删除一个键值对,并以元组返回删除键值对
students = {201901: '小明', 201902: '小红', 201903: '小强'}
key, value = students.popitem()
print(key, value)
print(students)
201903 小强
{201901: '小明', 201902: '小红'}
3、修改值
- 通过先索引后赋值的方式对相应的值进行修改
students = {201901: '小明', 201902: '小红', 201903: '小强'}
students[201902] = "小雪"
students
{201901: '小明', 201902: '小雪', 201903: '小强'}
4、d.get( )方法
d.get(key,default) 从字典d中获取键key对应的值,如果没有这个键,则返回default
- 小例子:统计"牛奶奶找刘奶奶买牛奶"中字符的出现频率
s = "牛奶奶找刘奶奶买牛奶"
d = {}
print(d)
for i in s:
d[i] = d.get(i, 0)+1
print(d)
# print(d)
{}
{'牛': 1}
{'牛': 1, '奶': 1}
{'牛': 1, '奶': 2}
{'牛': 1, '奶': 2, '找': 1}
{'牛': 1, '奶': 2, '找': 1, '刘': 1}
{'牛': 1, '奶': 3, '找': 1, '刘': 1}
{'牛': 1, '奶': 4, '找': 1, '刘': 1}
{'牛': 1, '奶': 4, '找': 1, '刘': 1, '买': 1}
{'牛': 2, '奶': 4, '找': 1, '刘': 1, '买': 1}
{'牛': 2, '奶': 5, '找': 1, '刘': 1, '买': 1}
5、d.keys( ) d.values( )方法
students = {201901: '小明', 201902: '小红', 201903: '小强'}
print(list(students.keys()))
print(list(students.values()))
[201901, 201902, 201903]
['小明', '小红', '小强']
6、d.items( )方法及字典的遍历
print(list(students.items()))
for k, v in students.items():
print(k, v)
[(201901, '小明'), (201902, '小红'), (201903, '小强')]
201901 小明
201902 小红
201903 小强
4.4 集合
4.4.1 集合的表达
- 一系列互不相等元素的无序集合
- 元素必须是不可变类型:数字,字符串或元组,可视作字典的键
- 可以看做是没有值,或者值为None的字典
students = {"小明", "小红", "小强", "小明"} #可用于去重
students
{'小强', '小明', '小红'}
4.4.2 集合的运算
- 小例子 通过集合进行交集并集的运算
Chinese_A = {"刘德华", "张学友", "张曼玉", "钟楚红", "古天乐", "林青霞"}
Chinese_A
{'刘德华', '古天乐', '张学友', '张曼玉', '林青霞', '钟楚红'}
Math_A = {"林青霞", "郭富城", "王祖贤", "刘德华", "张曼玉", "黎明"}
Math_A
{'刘德华', '张曼玉', '林青霞', '王祖贤', '郭富城', '黎明'}
- 语文和数学两门均为A的学员
- S & T 返回一个新集合,包括同时在集合S和T中的元素
Chinese_A & Math_A
{'刘德华', '张曼玉', '林青霞'}
- 语文或数学至少一门为A的学员
- S | T 返回一个新集合,包括集合S和T中的所有元素
Chinese_A | Math_A
{'刘德华', '古天乐', '张学友', '张曼玉', '林青霞', '王祖贤', '郭富城', '钟楚红', '黎明'}
- 语文数学只有一门为A的学员
- S ^ T 返回一个新集合,包括集合S和T中的非共同元素
Chinese_A ^ Math_A
{'古天乐', '张学友', '王祖贤', '郭富城', '钟楚红', '黎明'}
- 语文为A,数学不为A的学员
- S - T 返回一个新集合,包括在集合S但不在集合T中的元素
Chinese_A - Math_A
{'古天乐', '张学友', '钟楚红'}
- 数学为A,语文不为A的学员
Math_A - Chinese_A
{'王祖贤', '郭富城', '黎明'}
4.4.3 集合的操作方法
- 增加元素——S.add(x)
stars = {"刘德华", "张学友", "张曼玉"}
stars.add("王祖贤")
stars
{'刘德华', '张学友', '张曼玉', '王祖贤'}
- 移除元素——S.remove(x)
stars.remove("王祖贤")
stars
{'刘德华', '张学友', '张曼玉'}
- 集合的长度——len(S)
len(stars)
3
- 集合的遍历——借助for循环
for star in stars:
print(star)
张学友
张曼玉
刘德华
第五章 程序控制结构
非顺序式的程序控制,往往需要根据一定的条件,决定程序运行的路线。因此,我们首先来认识一下什么叫条件测试。
第一部分 条件测试
1、比较运算
a = 10
b = 8
print(a > b) # 大于
print(a < b) # 小于
print(a >= b) # 大于等于
print(a <= b) # 小于等于
print(a == b) # 等于
print(a != b) # 不等于
True
False
True
False
False
True
- 非空
ls = [1]
if ls: # 数据结构不为空、变量不为0、None、False 则条件成立
print("非空")
else:
print("空的")
非空
2、逻辑运算
- 与、或、非
a = 10
b = 8
c = 12
print((a > b) and (b > c)) # 与
print((a > b) or (b > c)) # 或
print(not(a > b)) # 非
False
True
False
- 复合逻辑运算的优先级
非 > 与 > 或
print(True or True and False)
True
print((True or True) and False)
False
3、存在运算
元素 in 列表/字符串
cars = ["BYD", "BMW", "AUDI", "TOYOTA"]
print("BMW" in cars)
print("BENZ" in cars)
True
False
元素 not in 列表/字符串
print("BMW" not in cars)
print("BENZ" not in cars)
False
True
第二部分 分支结构——if语句
1、单分支
模板
if 条件:
缩进的代码块
age = 8
if age > 7:
print("孩子,你该上学啦!")
孩子,你该上学啦!
2、二分支
模板
if 条件:
缩进的代码块
else:
缩进的代码块
age = 6
if age > 7:
print("孩子,你该上学啦!")
else:
print("再玩两年泥巴!")
再玩两年泥巴!
3、 多分支
模板
if 条件:
缩进的代码块
elif 条件:
缩进的代码块
elif 条件:
缩进的代码块
...
else:
缩进的代码块
age = 38
if age < 7:
print("再玩两年泥巴")
elif age < 13:
print("孩子,你该上小学啦")
elif age < 16:
print("孩子,你该上初中了")
elif age < 19:
print("孩子,你该上高中了")
elif age < 23:
print("大学生活快乐")
elif age < 60:
print("辛苦了,各行各业的工作者们")
else: # 有时为了清楚,也可以写成elif age >= 60:
print("享受退休生活吧")
辛苦了,各行各业的工作者们
不管多少分支,最后只执行一个分支
4、嵌套语句
题目:年满18周岁,在非公共场合方可抽烟,判断某种情形下是否可以抽烟
age = eval(input("请输入年龄"))
if age > 18:
is_public_place = bool(eval(input("公共场合请输入1,非公共场合请输入0")))
print(is_public_place)
if not is_public_place:
print("可以抽烟")
else:
print("禁止抽烟")
else:
print("禁止抽烟")
请输入年龄16
禁止抽烟
第三部分 遍历循环——for 循环
主要形式:
- for 元素 in 可迭代对象:
执行语句
执行过程:
- 从可迭代对象中,依次取出每一个元素,并进行相应的操作
1、直接迭代——列表[ ]、元组( )、集合{ }、字符串" "
graduates = ("李雷", "韩梅梅", "Jim")
for graduate in graduates:
print("Congratulations, "+graduate)
Congratulations, 李雷
Congratulations, 韩梅梅
Congratulations, Jim
2、变换迭代——字典
students = {201901: '小明', 201902: '小红', 201903: '小强'}
for k, v in students.items():
print(k, v)
for student in students.keys():
print(student)
201901 小明
201902 小红
201903 小强
201901
201902
201903
3、range()对象
res=[]
for i in range(10000):
res.append(i**2)
print(res[:5])
print(res[-1])
[0, 1, 4, 9, 16]
99980001
res=[]
for i in range(1,10,2):
res.append(i**2)
print(res)
[1, 9, 25, 49, 81]
循环控制:break 和 continue
- break 结束整个循环
product_scores = [89, 90, 99, 70, 67, 78, 85, 92, 77, 82] # 1组10个产品的性能评分
# 如果低于75分的超过1个,则该组产品不合格
i = 0
for score in product_scores:
if score < 75:
i += 1
if i == 2:
print("产品抽检不合格")
break
产品抽检不合格
- continue 结束本次循环
product_scores = [89, 90, 99, 70, 67, 78, 85, 92, 77, 82] # 1组10个产品的性能评分
# 如果低于75分,输出警示
print(len(product_scores))
for i in range(len(product_scores)):
if product_scores[i] >= 75:
continue
print("第{0}个产品,分数为{1},不合格".format(i, product_scores[i]))
10
第3个产品,分数为70,不合格
第4个产品,分数为67,不合格
for 与 else的配合
如果for 循环全部执行完毕,没有被break中止,则运行else块
product_scores = [89, 90, 99, 70, 67, 78, 85, 92, 77, 82] # 1组10个产品的性能评分
# 如果低于75分的超过1个,则该组产品不合格
i = 0
for score in product_scores:
if score < 75:
i+=1
if i == 2:
print("产品抽检不合格")
break
else:
print("产品抽检合格")
产品抽检不合格
第四部分 无限循环——while 循环
4.1 为什么要用while 循环
- 经典题目:猜数字
albert_age = 18
#第1次
guess = int(input(">>:"))
if guess > albert_age :
print("猜的太大了,往小里试试...")
elif guess < albert_age :
print("猜的太小了,往大里试试...")
else:
print("恭喜你,猜对了...")
#第2次
guess = int(input(">>:"))
if guess > albert_age :
print("猜的太大了,往小里试试...")
elif guess < albert_age :
print("猜的太小了,往大里试试...")
else:
print("恭喜你,猜对了...")
代码可能需要重复执行,可是又不知道具体要执行多少次
4.2 while循环的一般形式
主要形式:
- while 判断条件:
执行语句
条件为真,执行语句
条件为假,while 循环结束
albert_age = 18
guess = int(input(">>:"))
while guess != albert_age:
if guess > albert_age :
print("猜的太大了,往小里试试...")
elif guess < albert_age :
print("猜的太小了,往大里试试...")
guess = int(input(">>:"))
print("恭喜你,猜对了...")
4.3 while与风向标
albert_age = 18
flag = True # 布尔类型
while flag:
guess = int(input(">>:"))
if guess > albert_age :
print("猜的太大了,往小里试试...")
elif guess < albert_age :
print("猜的太小了,往大里试试...")
else:
print("恭喜你,猜对了...")
flag = False # 当诉求得到满足,就让风向变一下
flag=True
while flag:
pass
while flag:
pass
while flag:
flag=False # 循环逐层判断,当flag为false时,循环会逐层退出
4.4 while 与循环控制 break、continue
albert_age = 18
while True:
guess = int(input(">>:"))
if guess > albert_age :
print("猜的太大了,往小里试试...")
elif guess < albert_age :
print("猜的太小了,往大里试试...")
else:
print("恭喜你,猜对了...")
break # 当诉求得到满足,就跳出循环
输出10以内的奇数
i = 0
while i < 10:
i += 1
if i % 2 == 0:
continue # 跳出本次循环,进入下一次循环
print(i)
1
3
5
7
9
4.5 while与else
如果while 循环全部执行完毕,没有被break中止,则运行else块
count = 0
while count <= 5 :
count += 1
print("Loop",count)
else:
print("循环正常执行完啦")
Loop 1
Loop 2
Loop 3
Loop 4
Loop 5
Loop 6
循环正常执行完啦
4.6 再看两个例子
【小例子】删除列表中的特定值
pets = ["dog", "cat", "dog", "pig", "goldfish", "rabbit", "cat"]
while "cat" in pets:
pets.remove("cat")
pets
['dog', 'dog', 'pig', 'goldfish', 'rabbit']
【小例子】将未读书籍列表中书名分别输出后,存入已读书籍列表
not_read = ["红楼梦", "水浒传", "三国演义", "西游记"]
have_read = []
while not_read: # not_read非空,循环继续,否则中止
book = not_read.pop()
have_read.append(book)
print("我已经读过《{}》了".format(book))
print(not_read)
print(have_read)
我已经读过《西游记》了
我已经读过《三国演义》了
我已经读过《水浒传》了
我已经读过《红楼梦》了
[]
['西游记', '三国演义', '水浒传', '红楼梦']
第五部分 控制语句注意问题
5.1 尽可能减少多层嵌套
- 可读性差,容易把人搞疯掉
if 条件:
执行语句
if 条件:
执行语句
if...
5.2 避免死循环
条件一直成立,循环永无止境
# while True:
# print("天地之渺渺,时间之无限")
5.3 封装过于复杂的判断条件
如果条件判断里的表达式过于复杂
出现了太多的 not/and/or等
导致可读性大打折扣
考虑将条件封装为函数
a, b, c, d, e = 10, 8, 6, 2, 0
if (a > b) and (c >d) and (not e):
print("我已经晕鸟")
numbers = (10, 8, 6, 2, 0)
def judge(num):
a, b, c, d, e = num
x = a > b
y = c > d
z = not e
return x and y and z
if judge(numbers):
print("就是这个feel,biu倍儿爽")
就是这个feel,biu倍儿爽
第六章 函数
6.1 函数的定义及调用
6.1.1 为什么要用函数
1、提高代码复用性——抽象出来,封装为函数
2、将复杂的大问题分解成一系列小问题,分而治之——模块化设计的思想
3、利于代码的维护和管理
顺序式
# 5的阶乘
n = 5
res = 1
for i in range(1, n+1):
res *= i
print(res)
# 20的阶乘
n = 20
res = 1
for i in range(1, n+1):
res *= i
print(res)
120
2432902008176640000
抽象成函数
def factoria(n):
res = 1
for i in range(1,n+1):
res *= i
return res
print(factoria(5))
print(factoria(20))
120
2432902008176640000
6.1.2 函数的定义及调用
白箱子:输入——处理——输出
三要素:参数、函数体、返回值
1、定义
def 函数名(参数):
函数体
return 返回值
# 求正方形的面积
def area_of_square(length_of_side):
square_area = pow(length_of_side, 2)
return square_area
2、调用
函数名(参数)
area = area_of_square(5)
area
25
6.1.3 参数传递
0、形参与实参
-
形参(形式参数):函数定义时的参数,实际上就是变量名
-
实参(实际参数):函数调用时的参数,实际上就是变量的值
1、位置参数
-
严格按照位置顺序,用实参对形参进行赋值(关联)
-
一般用在参数比较少的时候
def function(x, y, z):
print(x, y, z)
function(1, 2, 3) # x = 1; y = 2; z = 3
1 2 3
- 实参与形参个数必须一一对应,一个不能多,一个不能少
function(1, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-2a7da6ff9675> in <module>
----> 1 function(1, 2)
TypeError: function() missing 1 required positional argument: 'z'
function(1, 2, 3, 4)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-748d3d0335e6> in <module>
----> 1 function(1, 2, 3, 4)
TypeError: function() takes 3 positional arguments but 4 were given
2、关键字参数
-
打破位置限制,直呼其名的进行值的传递(形参=实参)
-
必须遵守实参与形参数量上一一对应
-
多用在参数比较多的场合
def function(x, y, z):
print(x, y, z)
function(y=1, z=2, x=3) # x = 1; y = 2; z = 3
3 1 2
-
位置参数可以与关键字参数混合使用
-
但是,位置参数必须放在关键字参数前面
function(1, z=2, y=3)
1 3 2
function(1, 2, z=3)
1 2 3
- 不能为同一个形参重复传值
def function(x, y, z):
print(x, y, z)
function(1, z=2, x=3)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-f385272db011> in <module>
3
4
----> 5 function(1, z=2, x=3)
TypeError: function() got multiple values for argument 'x'
3、默认参数
-
在定义阶段就给形参赋值——该形参的常用值
-
在定义阶段就给形参赋值——该形参的常用值
-
默认参数必须放在非默认参数后面
-
调用函数时,可以不对该形参传值
-
机器学习库中类的方法里非常常见
def register(name, age, sex="male"):
print(name, age, sex)
register("大杰仔", 18)
大杰仔 18 male
- 也可以按正常的形参进行传值
register("林志玲", 38, "female")
林志玲 38 female
- 默认参数应该设置为不可变类型(数字、字符串、元组)
def function(ls=[]):
print(id(ls))
ls.append(1)
print(id(ls))
print(ls)
function()
1759752744328
1759752744328
[1]
function()
1759752744328
1759752744328
[1, 1]
function()
1759752744328
1759752744328
[1, 1, 1]
def function(ls="Python"):
print(id(ls))
ls += "3.7"
print(id(ls))
print(ls)
function()
1759701700656
1759754352240
Python3.7
function()
1759701700656
1759754353328
Python3.7
function()
1759701700656
1759754354352
Python3.7
- 让参数变成可选的
def name(first_name, last_name, middle_name=None):
if middle_name:
return first_name+middle_name+last_name
else:
return first_name+last_name
print(name("大","仔"))
print(name("大", "仔", "杰"))
大仔
大杰仔
*4、可变长参数 args
-
不知道会传过来多少参数 *args
-
该形参必须放在参数列表的最后
def foo(x, y, z, *args):
print(x, y ,z)
print(args)
foo(1, 2, 3, 4, 5, 6) # 多余的参数,打包传递给args
1 2 3
(4, 5, 6)
- 实参打散
def foo(x, y, z, *args):
print(x, y ,z)
print(args)
foo(1, 2, 3, [4, 5, 6])
1 2 3
([4, 5, 6],)
foo(1, 2, 3, *[4, 5, 6]) # 打散的是列表、字符串、元组或集合
1 2 3
(4, 5, 6)
**5、可变长参数 ****kwargs
def foo(x, y, z, **kwargs):
print(x, y ,z)
print(kwargs)
foo(1, 2, 3, a=4, b=5, c=6) # 多余的参数,以字典的形式打包传递给kwargs
1 2 3
{'a': 4, 'b': 5, 'c': 6}
- 字典实参打散
def foo(x, y, z, **kwargs):
print(x, y ,z)
print(kwargs)
foo(1, 2, 3, **{"a": 4, "b": 5, "c":6})
1 2 3
{'a': 4, 'b': 5, 'c': 6}
- 可变长参数的组合使用
def foo(*args, **kwargs):
print(args)
print(kwargs)
foo(1, 2, 3, a=4, b=5, c=6)
(1, 2, 3)
{'a': 4, 'b': 5, 'c': 6}
6.1.4 函数体与变量作用域
-
函数体就是一段只在函数被调用时,才会执行的代码,代码构成与其他代码并无不同
-
局部变量——仅在函数体内定义和发挥作用
def multipy(x, y):
z = x*y
return z
multipy(2, 9)
print(z) # 函数执行完毕,局部变量z已经被释放掉了
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-29-9a7fd4c4c0a9> in <module>
5
6 multipy(2, 9)
----> 7 print(z) # 函数执行完毕,局部变量z已经被释放掉了
NameError: name 'z' is not defined
-
全局变量——外部定义的都是全局变量
-
全局变量可以在函数体内直接被使用
n = 3
ls = [0]
def multipy(x, y):
z = n*x*y
ls.append(z)
return z
print(multipy(2, 9))
ls
54
[0, 54]
- 通过global 在函数体内定义全局变量
def multipy(x, y):
global z
z = x*y
return z
print(multipy(2, 9))
print(z)
18
18
6.1.5 返回值
1、单个返回值
def foo(x):
return x**2
res = foo(10)
res
100
2、多个返回值——以元组的形式
def foo(x):
return 1, x, x**2, x**3 # 逗号分开,打包返回
print(foo(3))
(1, 3, 9, 27)
a, b , c, d = foo(3) # 解包赋值
print(a)
print(b)
print(c)
print(d)
1
3
9
27
3、可以有多个return 语句,一旦其中一个执行,代表了函数运行的结束
def is_holiday(day):
if day in ["Sunday", "Saturday"]:
return "Is holiday"
else:
return "Not holiday"
print("啦啦啦德玛西亚,啦啦啦啦") # 你丫根本没机会运行。。。
print(is_holiday("Sunday"))
print(is_holiday("Monday"))
Is holiday
Not holiday
4、没有return语句,返回值为None
def foo():
print("我是孙悟空")
res = foo()
print(res)
我是孙悟空
None
6.1.6 几点建议
1、函数及其参数的命名参照变量的命名
-
字母小写及下划线组合
-
有实际意义
2、应包含简要阐述函数功能的注释,注释紧跟函数定义后面
def foo():
# 这个函数的作用是为了给大家瞅一瞅,你瞅啥,瞅你咋地。。。。
pass
3、函数定义前后各空两行
def f1():
pass
# 空出两行,以示清白
def f2():
pass
def f3(x=3): # 默认参数赋值等号两侧不需加空格
pass
# ...
4、默认参数赋值等号两侧不需加空格
5.2 函数式编程实例
模块化编程思想
- 自顶向下,分而治之
【问题描述】
-
小丹和小伟羽毛球打的都不错,水平也在伯仲之间,小丹略胜一筹,基本上,打100个球,小丹能赢55次,小伟能赢45次。
-
但是每次大型比赛(1局定胜负,谁先赢到21分,谁就获胜),小丹赢的概率远远大于小伟,小伟很是不服气。
-
亲爱的小伙伴,你能通过模拟实验,来揭示其中的奥妙吗?
【问题抽象】
1、在小丹Vs小伟的二元比赛系统中,小丹每球获胜概率55%,小伟每球获胜概率45%;
2、每局比赛,先赢21球(21分)者获胜;
3、假设进行n = 10000局独立的比赛,小丹会获胜多少局?(n 较大的时候,实验结果≈真实期望)
【问题分解】
def main():
# 主要逻辑
prob_A, prob_B, number_of_games = get_inputs() # 获取原始数据
win_A, win_B = sim_n_games(prob_A, prob_B, number_of_games) # 获取模拟结果
print_summary(win_A, win_B, number_of_games) # 结果汇总输出
1、输入原始数据
def get_inputs():
# 输入原始数据
prob_A = eval(input("请输入运动员A的每球获胜概率(0~1):"))
prob_B = round(1-prob_A, 2)
number_of_games = eval(input("请输入模拟的场次(正整数):"))
print("模拟比赛总次数:", number_of_games)
print("A 选手每球获胜概率:", prob_A)
print("B 选手每球获胜概率:", prob_B)
return prob_A, prob_B, number_of_games
** 单元测试**
prob_A, prob_B, number_of_games = get_inputs()
print(prob_A, prob_B, number_of_games)
请输入运动员A的每球获胜概率(0~1):0.55
请输入模拟的场次(正整数):10000
模拟比赛总次数: 10000
A 选手每球获胜概率: 0.55
B 选手每球获胜概率: 0.45
0.55 0.45 10000
2、多场比赛模拟
def sim_n_games(prob_A, prob_B, number_of_games):
# 模拟多场比赛的结果
win_A, win_B = 0, 0 # 初始化A、B获胜的场次
for i in range(number_of_games): # 迭代number_of_games次
score_A, score_B = sim_one_game(prob_A, prob_B) # 获得模拟依次比赛的比分
if score_A > score_B:
win_A += 1
else:
win_B += 1
return win_A, win_B
import random
def sim_one_game(prob_A, prob_B):
# 模拟一场比赛的结果
score_A, score_B = 0, 0
while not game_over(score_A, score_B):
if random.random() < prob_A: # random.random() 生产[0,1)之间的随机小数,均匀分布
score_A += 1
else:
score_B += 1
return score_A, score_B
def game_over(score_A, score_B):
# 单场模拟结束条件,一方先达到21分,比赛结束
return score_A == 21 or score_B == 21
** 单元测试 用assert——断言**
-
assert expression
-
表达式结果为 false 的时候触发异常
assert game_over(21, 8) == True
assert game_over(9, 21) == True
assert game_over(11, 8) == False
assert game_over(21, 8) == False
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-42-88b651626036> in <module>
2 assert game_over(9, 21) == True
3 assert game_over(11, 8) == False
----> 4 assert game_over(21, 8) == False
AssertionError:
print(sim_one_game(0.55, 0.45))
print(sim_one_game(0.7, 0.3))
print(sim_one_game(0.2, 0.8))
(21, 7)
(21, 14)
(10, 21)
print(sim_n_games(0.55, 0.45, 1000))
(731, 269)
3、结果汇总输出
def print_summary(win_A, win_B, number_of_games):
# 结果汇总输出
print("共模拟了{}场比赛".format(number_of_games))
print("选手A获胜{0}场,占比{1:.1%}".format(win_A, win_A/number_of_games))
print("选手B获胜{0}场,占比{1:.1%}".format(win_B, win_B/number_of_games))
print_summary(729, 271, 1000)
共模拟了1000场比赛
选手A获胜729场,占比72.9%
选手B获胜271场,占比27.1%
import random
def get_inputs():
# 输入原始数据
prob_A = eval(input("请输入运动员A的每球获胜概率(0~1):"))
prob_B = round(1-prob_A, 2)
number_of_games = eval(input("请输入模拟的场次(正整数):"))
print("模拟比赛总次数:", number_of_games)
print("A 选手每球获胜概率:", prob_A)
print("B 选手每球获胜概率:", prob_B)
return prob_A, prob_B, number_of_games
def game_over(score_A, score_B):
# 单场模拟结束条件,一方先达到21分,比赛结束
return score_A == 21 or score_B == 21
def sim_one_game(prob_A, prob_B):
# 模拟一场比赛的结果
score_A, score_B = 0, 0
while not game_over(score_A, score_B):
if random.random() < prob_A: # random.random() 生产[0,1)之间的随机小数,均匀分布
score_A += 1
else:
score_B += 1
return score_A, score_B
def sim_n_games(prob_A, prob_B, number_of_games):
# 模拟多场比赛的结果
win_A, win_B = 0, 0 # 初始化A、B获胜的场次
for i in range(number_of_games): # 迭代number_of_games次
score_A, score_B = sim_one_game(prob_A, prob_B) # 获得模拟依次比赛的比分
if score_A > score_B:
win_A += 1
else:
win_B += 1
return win_A, win_B
def print_summary(win_A, win_B, number_of_games):
# 结果汇总输出
print("共模拟了{}场比赛".format(number_of_games))
print("\033[31m选手A获胜{0}场,占比{1:.1%}".format(win_A, win_A/number_of_games))
print("选手B获胜{0}场,占比{1:.1%}".format(win_B, win_B/number_of_games))
def main():
# 主要逻辑
prob_A, prob_B, number_of_games = get_inputs() # 获取原始数据
win_A, win_B = sim_n_games(prob_A, prob_B, number_of_games) # 获取模拟结果
print_summary(win_A, win_B, number_of_games) # 结果汇总输出
if __name__ == "__main__":
main()
请输入运动员A的每球获胜概率(0~1):0.52
请输入模拟的场次(正整数):10000
模拟比赛总次数: 10000
A 选手每球获胜概率: 0.52
B 选手每球获胜概率: 0.48
共模拟了10000场比赛
[31m选手A获胜6033场,占比60.3%选手B获胜3967场,占比39.7%
经统计,小丹跟小伟14年职业生涯,共交手40次,小丹以28:12遥遥领先。
其中,两人共交战整整100局:
小丹获胜61局,占比61%;
小伟获胜39局,占比39%。
你以为你跟别人的差距只是一点点,实际上,差距老大了
5.3 匿名函数
1、基本形式
lambda 变量: 函数体
2、常用用法
在参数列表中最适合使用匿名函数,尤其是与key = 搭配
- 排序sort() sorted()
ls = [(93, 88), (79, 100), (86, 71), (85, 85), (76, 94)]
ls.sort()
ls
[(76, 94), (79, 100), (85, 85), (86, 71), (93, 88)]
ls.sort(key = lambda x: x[1])
ls
[(86, 71), (85, 85), (93, 88), (76, 94), (79, 100)]
ls = [(93, 88), (79, 100), (86, 71), (85, 85), (76, 94)]
temp = sorted(ls, key = lambda x: x[0]+x[1], reverse=True)
temp
[(93, 88), (79, 100), (85, 85), (76, 94), (86, 71)]
- max() min()
ls = [(93, 88), (79, 100), (86, 71), (85, 85), (76, 94)]
n = max(ls, key = lambda x: x[1])
n
(79, 100)
n = min(ls, key = lambda x: x[1])
n
(86, 71)
5.4 面向过程和面向对象
面向过程——以过程为中心的编程思想,以“什么正在发生”为主要目标进行编程。 冰冷的,程序化的
面向对象——将现实世界的事物抽象成对象,更关注“谁在受影响”,更加贴近现实。 有血有肉,拟人(物)化的
- 以公共汽车为例
“面向过程”:汽车启动是一个事件,汽车到站是另一个事件。。。。
在编程序的时候我们关心的是某一个事件,而不是汽车本身。
我们分别对启动和到站编写程序。
"面向对象":构造“汽车”这个对象。
对象包含动力、服役时间、生产厂家等等一系列的“属性”;
也包含加油、启动、加速、刹车、拐弯、鸣喇叭、到站、维修等一系列的“方法”。
通过对象的行为表达相应的事件