Python基础1

164 阅读47分钟

绪论

个人学习笔记,并且主要针对机器学习深度学习,可能会有增删改,不涉及其他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
  • 尽量避免用中文和拼音做变量名
  • 特殊的变量:常量(不变的量,如π\pi、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
  • 再进一步 修饰性输出
  1. 填充输出
# ____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场比赛
选手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 面向过程和面向对象

面向过程——以过程为中心的编程思想,以“什么正在发生”为主要目标进行编程。 冰冷的,程序化的

面向对象——将现实世界的事物抽象成对象,更关注“谁在受影响”,更加贴近现实。  有血有肉,拟人(物)化的

  • 以公共汽车为例

“面向过程”:汽车启动是一个事件,汽车到站是另一个事件。。。。

在编程序的时候我们关心的是某一个事件,而不是汽车本身。

我们分别对启动和到站编写程序。

"面向对象":构造“汽车”这个对象。

对象包含动力、服役时间、生产厂家等等一系列的“属性”;

也包含加油、启动、加速、刹车、拐弯、鸣喇叭、到站、维修等一系列的“方法”。

通过对象的行为表达相应的事件