Python

一、数据类型转换

函数 描述
int(x[,base]) 将x转换为一个整数
float(x) 将x转换到一个浮点数
complex(real [,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串

二、运算符优先级

运算符 描述
(expressions...),[expressions...], {key: value...}, {expressions...} 括号,索引/切片
x[index], x[index:index], x(arguments...), x.attribute 读取,切片,调用,属性引用
await x await 表达式
** 幂运算(指数)
+x, -x, ~x 正,负,按位取反 NOT
*, @, /, //, % 乘,矩阵乘,除,整除,取余
+, - 加,减
<<, >> 左移,右移
& 按位与(AND)
^ 按位异或(XOR)
` `
<, <=, >, >=,!=, ==, is,is not,in,not in, 比较运算,包括成员检测和标识号检测
not 逻辑非 NOT
and 逻辑与 AND
or 逻辑或 OR
if -- else 条件表达式
lambda lambda 表达式
:= = += -= *= 赋值表达式
  1. 同级运算符从左到右计算

  2. 使用括号可以改变运算顺序。在复杂表达式中,建议使用括号明确优先级,提高代码可读性

1.*3*1*3 表达式输出结果为?

​ 是3,因为**有更高的优先级

2.优先级顺序为 NOT、AND、OR

1
2
3
4
5
6
7
8
9
10
11
12
x = True
y = False
z = False

if not x or y:
print(1)
elif not x or not y and z:
print(2)
elif not x or y or not y and x:
print(3)
else:
print(4)

答案: 3

3.//得到的并不一定是整数类型的数,它与分母分子的数据类型有关系。

4.变量在使用前必须先”定义”(即赋予变量一个值),否则会出现错误

三、常用函数

数学函数

函数 返回值 ( 描述 )
abs(x) 返回数字的绝对值,如abs(-10) 返回 10
ceil(x) 返回数字的上入整数,如math.ceil(4.1) 返回 5
cmp(x, y) 如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1。 Python 3 已废弃,使用 (x>y)-(x<y) 替换
exp(x) 返回e的x次幂(ex),如math.exp(1) 返回2.718281828459045
fabs(x) 以浮点数形式返回数字的绝对值,如math.fabs(-10) 返回10.0
floor(x) 返回数字的下舍整数,如math.floor(4.9)返回 4
log(x) 如math.log(math.e)返回1.0,math.log(100,10)返回2.0
log10(x) 返回以10为基数的x的对数,如math.log10(100)返回 2.0
max(x1, x2,…) 返回给定参数的最大值,参数可以为序列。
min(x1, x2,…) 返回给定参数的最小值,参数可以为序列。
modf(x) 返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示。
pow(x, y) x**y 运算后的值。
round(x ,n) 返回浮点数 x 的四舍五入值,如给出 n 值,则代表舍入到小数点后的位数。其实准确的说是保留值将保留到离上一位更近的一端。
sqrt(x) 返回数字x的平方根。

三角函数

Python包括以下三角函数:

函数 描述
acos(x) 返回x的反余弦弧度值。
asin(x) 返回x的反正弦弧度值。
atan(x) 返回x的反正切弧度值。
atan2(y, x) 返回给定的 X 及 Y 坐标值的反正切值。
cos(x) 返回x的弧度的余弦值。
hypot(x, y) 返回欧几里德范数 sqrt(x * x + y * y)。
sin(x) 返回的x弧度的正弦值。
tan(x) 返回x弧度的正切值。
degrees(x) 将弧度转换为角度,如degrees(math.pi/2) , 返回90.0
radians(x) 将角度转换为弧度

数学常量

常量 描述
pi 数学常量 pi(圆周率,一般以π来表示)
e 数学常量 e,e即自然常数(自然常数)。

四、随机数

随机数函数

随机数可以用于数学,游戏,安全等领域中,还经常被嵌入到算法中,用以提高算法效率,并提高程序的安全性。

Python包含以下常用随机数函数:

函数 描述
choice(seq) 从序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数。
randrange ([start,] stop [,step]) 从指定范围内,按指定基数递增的集合中获取一个随机数,基数默认值为 1
[random() 随机生成下一个实数,它在[0,1)范围内。
seed([x]) 改变随机数生成器的种子seed。如果你不了解其原理,你不必特别去设定seed,Python会帮你选择seed。
shuffle(lst) 将序列的所有元素随机排序
uniform(x, y) 随机生成下一个实数,它在[x,y]范围内。

Python 提供了多种用于生成随机数的函数,

1
import random
1. choice(seq):

该函数从序列(如列表、字符串、元组)中随机选取一个元素并返回。

示例代码:

1
2
3
4
5
import random

fruits = ["apple", "banana", "cherry", "orange"]
fruit = random.choice(fruits)
print("随机选取的水果:", fruit)

:::warning:::

random.choice需要一个序列(如列表、元组或字符串)作为参数,而不是多个独立的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#错误示例:
import random
def generate_unique_question(used_questions):
max_attempts = 100
for _ in range(max_attempts):
num1 = random.randint(1,99)
num2 = random.randint(1,99)
operator = random.choice('+','-')
#报错TypeError: Random.choice() takes 2 positional arguments but 3 were given

#正确写法:
import random
def generate_unique_question(used_questions):
max_attempts = 100
for _ in range(max_attempts):
num1 = random.randint(1,99)
num2 = random.randint(1,99)
operator = random.choice(['+','-']) # 修改:将运算符放在列表中
2. randrange(start, stop=None, step=1):

该函数在指定范围内(包括 start,不包括 stop)生成随机整数。如果未提供 stop,则默认值为 start,并从 0 开始生成随机整数。

示例代码:

1
2
3
4
5
6
number = random.randrange(5, 15)
print("生成的随机整数:", number)

# 从0开始生成10个随机整数
numbers = [random.randrange(10) for _ in range(10)]
print("生成的随机整数列表:", numbers)
3. random():

该函数生成一个介于 0.0 和 1.0 之间的均匀随机浮点数。

示例代码:

1
2
3
4
5
6
random_float = random.random()
print("生成的随机浮点数:", random_float)

# 生成10个随机浮点数
floats = [random.random() for _ in range(10)]
print("生成的随机浮点数列表:", floats)
4. seed(a):

该函数用于设置随机数生成器的种子。相同的种子会生成相同的随机数序列。

当不设置随机数种子 (seed) 时,Python 的 random 模块会自动使用系统当前时间作为种子。一般情况下没必要自己设置种子值

示例代码:

1
2
3
4
5
6
7
random.seed(10)  # 设置种子
number_1 = random.randint(1, 10)
print("生成的随机整数:", number_1)

random.seed(10) # 再次使用相同的种子
number_2 = random.randint(1, 10)
print("再次生成的随机整数:", number_2)
5. shuffle(lst):

该函数将序列中的元素随机打乱。

示例代码:

1
2
3
cards = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
random.shuffle(cards)
print("随机打乱后的牌:", cards)
6. uniform(a, b):

该函数生成一个介于 ab 之间的均匀随机浮点数。

示例代码:

1
2
3
4
5
6
random_number = random.uniform(2.5, 5.0)
print("生成的随机浮点数:", random_number)

# 生成10个随机浮点数
numbers = [random.uniform(1, 5) for _ in range(10)]
print("生成的随机浮点数列表:", numbers)

五、字符串

1.Python 字符串运算符

下表实例变量 a 值为字符串 “Hello”,b 变量值为 “Python”:

操作符 描述 实例
+ 字符串连接 a + b 输出结果: HelloPython
* 重复输出字符串 a*2 输出结果:HelloHello
[] 通过索引获取字符串中字符 a[1] 输出结果 e
[ : ] 截取字符串中的一部分,遵循左闭右开原则,str[0:2] 是不包含第 3 个字符的。 a[1:4] 输出结果 ell
in 成员运算符 - 如果字符串中包含给定的字符返回 True ‘H’ in a 输出结果 True
not in 成员运算符 - 如果字符串中不包含给定的字符返回 True ‘M’ not in a 输出结果 True
r/R 原始字符串 - 原始字符串:所有的字符串都是直接按照字面的意思来使用,没有转义特殊或不能打印的字符。 原始字符串除在字符串的第一个引号前加上字母 r(可以大小写)以外,与普通字符串有着几乎完全相同的语法。 print( r'\n' ) print( R'\n' )

2.Python 字符串格式化

Python 支持格式化字符串的输出 。尽管这样可能会用到非常复杂的表达式,但最基本的用法是将一个值插入到一个有字符串格式符 %s 的字符串中。

在 Python 中,字符串格式化使用与 C 中 sprintf 函数一样的语法。

python字符串格式化符号:

符 号 描述
%c 格式化字符及其ASCII码
%s 格式化字符串
%d 格式化整数
%u 格式化无符号整型
%o 格式化无符号八进制数
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度
%e 用科学计数法格式化浮点数
%E 作用同%e,用科学计数法格式化浮点数
%g %f和%e的简写
%G %f 和 %E 的简写
%p 用十六进制数格式化变量的地址

格式化操作符辅助指令:

符号 功能
* 定义宽度或者小数点精度
- 用做左对齐
+ 在正数前面显示加号( + )
在正数前面显示空格
# 在八进制数前面显示零(‘0’),在十六进制前面显示’0x’或者’0X’(取决于用的是’x’还是’X’)
0 显示的数字前面填充’0’而不是默认的空格
% ‘%%’输出一个单一的’%’
(var) 映射变量(字典参数)
m.n. m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话)

Python2.6 开始,新增了一种格式化字符串的函数 str.format(),它增强了字符串格式化的功能。

3.format格式化函数

Python2.6 开始,新增了一种格式化字符串的函数 **str.format()**,它增强了字符串格式化的功能。

基本语法是通过 {}: 来代替以前的 %

format 函数可以接受不限个参数,位置可以不按顺序。

实例

1
2
3
4
5
6
7
8
>>>"{} {}".format("hello", "world")    # 不设置指定位置,按默认顺序
'hello world'

>>> "{0} {1}".format("hello", "world") # 设置指定位置
'hello world'

>>> "{1} {0} {1}".format("hello", "world") # 设置指定位置
'world hello world'

也可以设置参数:

实例

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/python
# -*- coding: UTF-8 -*-

print("网站名:{name}, 地址 {url}".format(name="菜鸟教程", url="www.runoob.com"))

# 通过字典设置参数
site = {"name": "菜鸟教程", "url": "www.runoob.com"}
print("网站名:{name}, 地址 {url}".format(**site))

# 通过列表索引设置参数
my_list = ['菜鸟教程', 'www.runoob.com']
print("网站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必须的

也可以向 str.format() 传入对象:

1
2
3
4
5
6
7
8
#!/usr/bin/python
# -*- coding: UTF-8 -*-

class AssignValue(object):
def __init__(self, value):
self.value = value
my_value = AssignValue(6)
print('value 为: {0.value}'.format(my_value)) # "0" 是可选的

4.数字格式化

下表展示了 str.format() 格式化数字的多种方法:

1
2
>>> print("{:.2f}".format(3.1415926))
3.14
数字 格式 输出 描述
3.1415926 {:.2f} 3.14 保留小数点后两位
3.1415926 {:+.2f} +3.14 带符号保留小数点后两位
-1 {:-.2f} -1.00 带符号保留小数点后两位
2.71828 {:.0f} 3 不带小数
5 {:0>2d} 05 数字补零 (填充左边, 宽度为2)
5 {:x<4d} 5xxx 数字补x (填充右边, 宽度为4)
10 {:x<4d} 10xx 数字补x (填充右边, 宽度为4)
1000000 {:,} 1,000,000 以逗号分隔的数字格式
0.25 {:.2%} 25.00% 百分比格式
1000000000 {:.2e} 1.00e+09 指数记法
13 {:>10d} 13 右对齐 (默认, 宽度为10)
13 {:<10d} 13 左对齐 (宽度为10)
13 {:^10d} 13 中间对齐 (宽度为10)
11 '{:b}'.format(11) '{:d}'.format(11) '{:o}'.format(11) '{:x}'.format(11) '{:#x}'.format(11) '{:#X}'.format(11) 1011 11 13 b 0xb 0XB 进制

^, <**, **> 分别是居中、左对齐、右对齐,后面带宽度, : 号后面带填充的字符,只能是一个字符,不指定则默认是用空格填充。

+ 表示在正数前显示 **+**,负数前显示 **-**; (空格)表示在正数前加空格

b、d、o、x 分别是二进制、十进制、八进制、十六进制。

此外我们可以使用大括号 {} 来转义大括号,如下实例:

实例

1
2
3
4
#!/usr/bin/python
# -*- coding: UTF-8 -*-

print ("{} 对应的位置是 {{0}}".format("runoob"))

输出结果为:

1
runoob 对应的位置是 {0}

5.f-string

f-string 是 python3.6 之后版本添加的,称之为字面量格式化字符串,是新的格式化字符串的语法。

之前我们习惯用百分号 (%):

实例

1
2
3
>>> name = 'Runoob'
>>> 'Hello %s' % name
'Hello Runoob'

f-string 格式化字符串以 f 开头,后面跟着字符串,字符串中的表达式用大括号 {} 包起来,它会将变量或表达式计算后的值替换进去,实例如下:

1
2
3
4
5
6
7
8
9
>>> name = 'Runoob'
>>> f'Hello {name}' # 替换变量
'Hello Runoob'
>>> f'{1+2}' # 使用表达式
'3'

>>> w = {'name': 'Runoob', 'url': 'www.runoob.com'}
>>> f'{w["name"]}: {w["url"]}'
'Runoob: www.runoob.com'

用了这种方式明显更简单了,不用再去判断使用 %s,还是 %d。

在 Python 3.8 的版本中可以使用 = 符号来拼接运算表达式与结果:

1
2
3
4
5
6
7
>>> x = 1
>>> print(f'{x+1}') # Python 3.6
2

>>> x = 1
>>> print(f'{x+1=}') # Python 3.8
x+1=2

6.Unicode 字符串

在Python2中,普通字符串是以8位ASCII码进行存储的,而Unicode字符串则存储为16位unicode字符串,这样能够表示更多的字符集。使用的语法是在字符串前面加上前缀 u

在Python3中,所有的字符串都是Unicode字符串。


7.Python 的字符串内建函数

Python 的字符串常用内建函数如下:

序号 方法及描述
1 capitalize() 将字符串的第一个字符转换为大写
2 center(width, fillchar)返回一个指定的宽度 width 居中的字符串,fillchar 为填充的字符,默认为空格。
3 count(str, beg= 0,end=len(string)) 返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
4 bytes.decode(encoding=”utf-8”, errors=”strict”) Python3 中没有 decode 方法,但我们可以使用 bytes 对象的 decode() 方法来解码给定的 bytes 对象,这个 bytes 对象可以由 str.encode() 来编码返回。
5 encode(encoding=’UTF-8’,errors=’strict’) 以 encoding 指定的编码格式编码字符串,如果出错默认报一个ValueError 的异常,除非 errors 指定的是’ignore’或者’replace’
6 endswith(suffix, beg=0, end=len(string)) 检查字符串是否以 suffix 结束,如果 beg 或者 end 指定则检查指定的范围内是否以 suffix 结束,如果是,返回 True,否则返回 False。
7 expandtabs(tabsize=8) 把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8 。
8 find(str, beg=0, end=len(string)) 检测 str 是否包含在字符串中,如果指定范围 beg 和 end ,则检查是否包含在指定范围内,如果包含返回开始的索引值,否则返回-1
9 index(str, beg=0, end=len(string)) 跟find()方法一样,只不过如果str不在字符串中会报一个异常。
10 isalnum() 检查字符串是否由字母和数字组成,即字符串中的所有字符都是字母或数字。如果字符串至少有一个字符,并且所有字符都是字母或数字,则返回 True;否则返回 False。
11 isalpha() 如果字符串至少有一个字符并且所有字符都是字母或中文字则返回 True, 否则返回 False
12 isdigit() 如果字符串只包含数字则返回 True 否则返回 False..
13 islower() 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
14 isnumeric() 如果字符串中只包含数字字符,则返回 True,否则返回 False
15 isspace() 如果字符串中只包含空白,则返回 True,否则返回 False.
16 istitle() 如果字符串是标题化的(见 title())则返回 True,否则返回 False
17 isupper() 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
18 join(seq) 以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
19 len(string) 返回字符串长度
20 [ljust(width[, fillchar])]返回一个原字符串左对齐,并使用 fillchar 填充至长度 width 的新字符串,fillchar 默认为空格。
21 lower() 转换字符串中所有大写字符为小写.
22 lstrip() 截掉字符串左边的空格或指定字符。
23 maketrans() 创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
24 max(str) 返回字符串 str 中最大的字母。
25 min(str) 返回字符串 str 中最小的字母。
26 [replace(old, new [, max])] 把 将字符串中的 old 替换成 new,如果 max 指定,则替换不超过 max 次。
27 rfind(str, beg=0,end=len(string)) 类似于 find()函数,不过是从右边开始查找.
28 rindex( str, beg=0, end=len(string)) 类似于 index(),不过是从右边开始.
29 [rjust(width,, fillchar]) 返回一个原字符串右对齐,并使用fillchar(默认空格)填充至长度 width 的新字符串
30 rstrip() 删除字符串末尾的空格或指定字符。
31 split(str=””, num=string.count(str)) 以 str 为分隔符截取字符串,如果 num 有指定值,则仅截取 num+1 个子字符串
32 [splitlines(keepends]) 按照行(‘\r’, ‘\r\n’, \n’)分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
33 startswith(substr, beg=0,end=len(string)) 检查字符串是否是以指定子字符串 substr 开头,是则返回 True,否则返回 False。如果beg 和 end 指定值,则在指定范围内检查。
34 [strip([chars])]在字符串上执行 lstrip()和 rstrip()
35 swapcase() 将字符串中大写转换为小写,小写转换为大写
36 title() 返回”标题化”的字符串,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())
37 translate(table, deletechars=””) 根据 table 给出的表(包含 256 个字符)转换 string 的字符, 要过滤掉的字符放到 deletechars 参数中
38 upper() 转换字符串中的小写字母为大写
39 zfill (width) 返回长度为 width 的字符串,原字符串右对齐,前面填充0
40 isdecimal() 检查字符串是否只包含十进制字符,如果是返回 true,否则返回 false。

六、列表

1
2
3
list2 = ['鍛戒', '护琛', '屽帮', '細', 111, 55.7, 5 + 4j]
print(list2[-3:-1]) # 顺序还是从左往右一个一个拿的,只不过用的编号是从右往左的
# 依旧遵循左闭右开原则(-3对应的取 -1对应的不取)

1.Python列表函数&方法

Python包含以下函数:

序号 函数
1 len(list) 列表元素个数
2 max(list) 返回列表元素最大值
3 min(list) 返回列表元素最小值
4 list(seq) 将元组转换为列表

Python包含以下方法:

序号 方法
1 [list.append(obj)] 在列表末尾添加新的对象
2 [list.count(obj)] 统计某个元素在列表中出现的次数
3 [list.extend(seq)]在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
4 [list.index(obj)]从列表中找出某个值第一个匹配项的索引位置
5 [list.insert(index, obj)] 将对象插入列表
6 [list.pop([index=-1])] 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
7 [list.remove(obj) 移除列表中某个值的第一个匹配项
8 [list.reverse()]反向列表中元素
9 [list.sort( key=None, reverse=False)] 对原列表进行排序
10 [list.clear()]清空列表
11 [list.copy()]复制列表

2.遍历

序列中遍历时,索引位置和对应值可以使用 enumerate() 函数同时得到:

1
2
3
4
5
6
>>> for i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
0 tic
1 tac
2 toe

同时遍历两个或更多的序列,可以使用 zip() 组合:

1
2
3
4
5
6
7
8
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
... print('What is your {0}? It is {1}.'.format(q, a))
...
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favorite color? It is blue.

要反向遍历一个序列,首先指定这个序列,然后调用 reversed() 函数:

1
2
3
4
5
6
7
8
>>> for i in reversed(range(1, 10, 2)):
... print(i)
...
9
7
5
3
1

要按顺序遍历一个序列,使用 sorted() 函数返回一个已排序的序列,并不修改原值:

1
2
3
4
5
6
7
8
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
... print(f)
...
apple
banana
orange
pear

七、operator

Python3 operator 模块

Python2.x 版本中,使用 cmp() 函数来比较两个列表、数字或字符串等的大小关系。

Python 3.X 的版本中已经没有 cmp() 函数,如果你需要实现比较功能,需要引入 operator 模块,适合任何对象,包含的方法有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# operator 模块包含的方法
import operator
operator.lt(a, b)
operator.le(a, b)
operator.eq(a, b)
operator.ne(a, b)
operator.ge(a, b)
operator.gt(a, b)
operator.__lt__(a, b)
operator.__le__(a, b)
operator.__eq__(a, b)
operator.__ne__(a, b)
operator.__ge__(a, b)
operator.__gt__(a, b)

这些直接看源码就行了,源码那写的很清楚,没必要记。

运算符函数

operator 模块提供了一套与 Python 的内置运算符对应的高效率函数。例如,operator.add(x, y) 与表达式 x+y 相同。

函数包含的种类有:对象的比较运算、逻辑运算、数学运算以及序列运算。

对象比较函数适用于所有的对象,函数名根据它们对应的比较运算符命名。

许多函数名与特殊方法名相同,只是没有双下划线。为了向后兼容性,也保留了许多包含双下划线的函数,为了表述清楚,建议使用没有双下划线的函数。

运算 语法 函数
加法 a + b add(a, b)
字符串拼接 seq1 + seq2 concat(seq1, seq2)
包含测试 obj in seq contains(seq, obj)
除法 a / b truediv(a, b)
除法 a // b floordiv(a, b)
按位与 a & b and_(a, b)
按位异或 a ^ b xor(a, b)
按位取反 ~ a invert(a)
按位或 `a b`
取幂 a ** b pow(a, b)
标识 a is b is_(a, b)
标识 a is not b is_not(a, b)
索引赋值 obj[k] = v setitem(obj, k, v)
索引删除 del obj[k] delitem(obj, k)
索引取值 obj[k] getitem(obj, k)
左移 a << b lshift(a, b)
取模 a % b mod(a, b)
乘法 a * b mul(a, b)
矩阵乘法 a @ b matmul(a, b)
取反(算术) - a neg(a)
取反(逻辑) not a not_(a)
正数 + a pos(a)
右移 a >> b rshift(a, b)
切片赋值 seq[i:j] = values setitem(seq, slice(i, j), values)
切片删除 del seq[i:j] delitem(seq, slice(i, j))
切片取值 seq[i:j] getitem(seq, slice(i, j))
字符串格式化 s % obj mod(s, obj)
减法 a - b sub(a, b)
真值测试 obj truth(obj)
比较 a < b lt(a, b)
比较 a <= b le(a, b)
相等 a == b eq(a, b)
不等 a != b ne(a, b)
比较 a >= b ge(a, b)
比较 a > b gt(a, b)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 示例
# add(), sub(), mul()

# 导入 operator 模块
import operator

# 初始化变量
a = 4

b = 3

# 使用 add() 让两个值相加
print ("add() 运算结果 :",end="");
print (operator.add(a, b))

# 使用 sub() 让两个值相减
print ("sub() 运算结果 :",end="");
print (operator.sub(a, b))

# 使用 mul() 让两个值相乘
print ("mul() 运算结果 :",end="");
print (operator.mul(a, b))

image-20240930152239421

八、函数

1.函数基本格式

1
2
def 函数名(参数列表):
函数体

函数的参数不需要显式指定数据类型,只写名字即可

函数的参数是可选的,你可以定义一个函数并为其指定参数,但在调用函数时并不一定要传入这些参数。如果你在函数定义中指定了参数,但在调用函数时没有传入任何参数,那么这个参数会采用默认值或者是 None。

1
2
3
4
5
6
7
8
9
def hello(str1):
if (str(str1) == 'hello'):
print("hello")
else:
print("......")
return

hello('hello')
hello(hello)

第二次调用的时候把hello函数本身传入了,然后转换成字符串类型进行比较:

在 Python 中,将函数转换为字符串类型时,会得到函数的地址或引用。这个地址或引用可以通过 str() 函数或者 repr() 函数来获取。所以当我们将一个函数像 hello 传递给另一个函数时,实际上传递的是函数对象本身,而不是函数的字符串表示。

如果尝试在 Python 中将一个函数对象转换为字符串,会得到类似 <function hello at 0x0123456789ABCDEF> 这样的字符串。这个字符串包含了函数的名称和在内存中的地址。

2.缺省参数与可变参数

缺省参数

1
2
3
4
5
def print_stu_information(name,age=24,gender='女'):
print(f"学生姓名:{name},年龄{age},性别{gender}")

print_stu_information("张三")#后俩参数有缺省值,可以不传入
print_stu_information("李四",gender='男')

可变参数

1
2
3
4
def myprint(*a):
print(a)#可以看出传入了一个元组

myprint(1,5,6,7,9,4,55)

3.lambda表达式

lambda 关键字用于创建小巧的匿名函数。lambda a, b: a+b 函数返回两个参数的和。Lambda 函数可用于任何需要函数对象的地方。在语法上,匿名函数只能是单个表达式。在语义上,它只是常规函数定义的语法糖。与嵌套函数定义一样,lambda 函数可以引用包含作用域中的变量

1
2
3
4
5
def make(n):
return lambda x : x + n

lst = make(42)
print(lst)

当执行 lst = make(42) 时:

​ n 的值被设置为42

​ 函数返回一个lambda函数,这个lambda函数被赋值给 lst

​ 此时 lst 实际上变成了一个新的函数:lambda x: x + 42

上例用 lambda 表达式返回函数。还可以把匿名函数用作传递的实参:

1
2
3
4
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pair: pair[1])
print(pairs)
#[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

九、python解释器

在 Python 中,可以通过以下方式来确定当前使用的是哪种 Python 解释器:

  1. 通过 platform 模块

    • 使用platform模块可以获取关于操作系统、Python 版本和解释器的信息。在 Python shell 或脚本中执行以下代码可以查看当前使用的 Python 解释器:

      1
      2
      import platform
      print(platform.python_implementation())
  2. 通过 sys 模块

    • 另一种方法是使用sys模块,其中 sys.implementation属性提供了有关当前 Python 解释器的信息。

      1
      2
      import sys
      print(sys.implementation.name)

十、元组

1.

Python 的元组与列表类似,不同之处在于元组的元素不能修改。

元组使用小括号 **( )**,列表使用方括号 **[ ]**。

元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。

2.空元组

创建空元组

1
tup1 = ()

3.单元素元组

元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运算符使用:

1
2
tup1 = (50)
type(tup1) # 不加逗号,类型为整型

<**class** ‘int’>

1
2
tup1 = (50,)
type(tup1) # 加上逗号,类型为元组

<**class** ‘tuple’>

4.访问

元组与字符串类似,下标索引从 0 开始,可以进行截取,组合等。

元组可以使用下标索引来访问元组中的值

5.修改?

元组中的元素值是不允许修改的,但我们可以对元组进行连接组合,如下实例:

1
2
3
4
5
6
7
8
9
tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')

# 以下修改元组元素操作是非法的。
# tup1[0] = 100

# 创建一个新的元组
tup3 = tup1 + tup2
print (tup3)

(12, 34.56, ‘abc’, ‘xyz’)

6.删除

元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组

1
2
3
4
5
6
tup = ('Google', 'Runoob', 1997, 2000)

print (tup)
del tup
print ("删除后的元组 tup : ")
print (tup)

以上实例元组被删除后,输出变量会有异常信息,输出如下所示:

1
2
3
4
5
删除后的元组 tup : 
Traceback (most recent call last):
File "test.py", line 8, in <module>
print (tup)
NameError: name 'tup' is not defined

7.元组运算符

与字符串一样,元组之间可以使用 **++=**和 ***** 号进行运算。这就意味着他们可以组合和复制,运算后会生成一个新的元组。

Python 表达式 结果 描述
len((1, 2, 3)) 3 计算元素个数
>>> a = (1, 2, 3) >>> b = (4, 5, 6) >>> c = a+b >>> c (1, 2, 3, 4, 5, 6) (1, 2, 3, 4, 5, 6) 连接,c 就是一个新的元组,它包含了 a 和 b 中的所有元素。
>>> a = (1, 2, 3) >>> b = (4, 5, 6) >>> a += b >>> a (1, 2, 3, 4, 5, 6) (1, 2, 3, 4, 5, 6) 连接,a 就变成了一个新的元组,它包含了 a 和 b 中的所有元素。
('Hi!',) * 4 (‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’) 复制
3 in (1, 2, 3) True 元素是否存在
for x in (1, 2, 3): print (x, end=" ") 1 2 3 迭代

8.元组索引,截取

元组也是一个序列,所以我们可以访问元组中的指定位置的元素,也可以截取索引中的一段元素

元组:

1
tup = ('Google', 'Runoob', 'Taobao', 'Wiki', 'Weibo','Weixin')
Python 表达式 结果 描述
tup[1] ‘Runoob’ 读取第二个元素
tup[-2] ‘Weibo’ 反向读取,读取倒数第二个元素
tup[1:] (‘Runoob’, ‘Taobao’, ‘Wiki’, ‘Weibo’, ‘Weixin’) 截取元素,从第二个开始后的所有元素。
tup[1:4] (‘Runoob’, ‘Taobao’, ‘Wiki’) 截取元素,从第二个开始到第四个元素(索引为 3)。

运行实例如下:

1
2
3
4
5
6
7
8
9
10
>>> tup = ('Google', 'Runoob', 'Taobao', 'Wiki', 'Weibo','Weixin')
>>> tup[1]
'Runoob'
>>> tup[-2]
'Weibo'
>>> tup[1:]
('Runoob', 'Taobao', 'Wiki', 'Weibo', 'Weixin')
>>> tup[1:4]
('Runoob', 'Taobao', 'Wiki')
>>>

9.元组内置函数

Python元组包含了以下内置函数

序号 方法及描述 实例
1 len(tuple) 计算元组元素个数。 >>> tuple1 = ('Google', 'Runoob', 'Taobao') >>> len(tuple1) 3 >>>
2 max(tuple) 返回元组中元素最大值。 >>> tuple2 = ('5', '4', '8') >>> max(tuple2) '8' >>>
3 min(tuple) 返回元组中元素最小值。 >>> tuple2 = ('5', '4', '8') >>> min(tuple2) '4' >>>
4 tuple(iterable) 将可迭代系列转换为元组。 >>> list1= ['Google', 'Taobao', 'Runoob', 'Baidu'] >>> tuple1=tuple(list1) >>> tuple1 ('Google', 'Taobao', 'Runoob', 'Baidu')

关于元组是不可变的

所谓元组的不可变指的是元组所指向的内存中的内容不可变。

1
2
3
4
5
6
7
8
9
10
>>> tup = ('r', 'u', 'n', 'o', 'o', 'b')
>>> tup[0] = 'g' # 不支持修改元素
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> id(tup) # 查看内存地址
4440687904
>>> tup = (1,2,3)
>>> id(tup)
4441088800 # 内存地址不一样了

从以上实例可以看出,重新赋值的元组 tup,绑定到新的对象了,不是修改了原来的对象。

tips:

在 Python 中,有一些数据类型是不可变的,包括字符串(strings)、元组(tuples)和数值类型(numbers)。这意味着一旦创建了这些对象,它们的值是无法更改的,任何修改操作都会创建一个新的对象而不是直接修改原始对象。

  1. Strings (字符串):

    • 字符串是不可变的,一旦创建就不能被修改。例如:

      1
      2
      s = "Hello"
      s[0] = "h" # 这将导致 TypeError 错误,因为字符串不可修改
  2. Tuples (元组):

    • 元组是不可变的有序集合,一旦创建就不能被修改。例如:

      1
      2
      t = (1, 2, 3)
      t[0] = 4 # 这将导致 TypeError 错误,因为元组不可修改
  3. Numbers (数字):

    • 数字类型包括整数、浮点数和复数等,它们都是不可变的。例如:

      1
      2
      x = 5
      x = x + 1 # 这里实际上是创建了一个新的整数对象来存储结果,而不是修改原来的对象

因为这些对象是不可变的,所以当你对它们进行修改时,实际上是创建了一个新的对象。这种不可变性有助于确保数据的安全性和一致性,同时也影响了对这些对象的操作方式。

十一、字典

1.创建

理解字典的最佳方式是把它看做无序的键=>值对集合。在同一个字典之内,关键字必须是互不相同。

一对大括号创建一个空的字典:{}。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>>> list(tel.keys())
['irv', 'guido', 'jack']
>>> sorted(tel.keys())
['guido', 'irv', 'jack']
>>> 'guido' in tel
True
>>> 'jack' not in tel
False

构造函数 dict() 直接从键值对元组列表中构建字典。如果有固定的模式,列表推导式指定特定的键值对:

1
2
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}

此外,字典推导可以用来创建任意键和值的表达式词典:

1
2
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

如果关键字只是简单的字符串,使用关键字参数指定键值对有时候更方便:

1
2
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098, 'guido': 4127}

2.遍历

在字典中遍历时,关键字和对应的值可以使用 items() 方法同时解读出来:

1
2
3
4
5
6
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
... print(k, v)
...
gallahad the pure
robin the brave

十二、模块

随着程序越来越长,为了方便维护,最好把脚本拆分成多个文件。编写脚本还一个好处,不同程序调用同一个函数时,不用把函数定义复制到各个程序。

为实现这些需求,Python 把各种定义存入一个文件,在脚本或解释器的交互式实例中使用。这个文件就是 模块 ;模块中的定义可以 导入 到其他模块或 模块(在顶层和计算器模式下,执行脚本中可访问的变量集)。

模块是包含 Python 定义和语句的文件。其文件名是模块名加后缀名 .py 。在模块内部,通过全局变量 __name__ 可以获取模块名(即字符串)。例如,用文本编辑器在当前目录下创建 fibo.py 文件,输入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#返回斐波那契数列直到n
def fib1(n):
a,b = 0,1
result = list()
for i in range(1,n+1):
result.append(a)
a,b = b, a+b
return result

#打印斐波那契数列直到n
def fib2(n):
a,b = 0,1
for i in range(1,n+1):
print(a,end=" ")
a,b = b,a+b

现在,进入 Python 解释器,用以下命令导入该模块:

1
import fibo

此操作不会直接把 fibo 中定义的函数名称添加到当前namespace中;它只是将模块名称``fibo`添加到那里。使用该模块名称可以访问其中的函数:

1
2
3
4
5
fibo.fib(1000)

fibo.fib2(100)

fibo.__name__

如果经常使用某个函数,可以把它赋值给局部变量:

1
2
fib = fibo.fib
fib(500)

12.1. 模块详解

模块包含可执行语句及函数定义。这些语句用于初始化模块,且仅在 import 语句 第一次 遇到模块名时执行。(文件作为脚本运行时,也会执行这些语句。)

每个模块都有自己的私有命名空间,它会被用作模块中定义的所有函数的全局命名空间。 因此,模块作者可以在模块内使用全局变量而不必担心与用户的全局变量发生意外冲突。 另一方面,如果你知道要怎么做就可以通过与引用模块函数一样的标记法 模块名.变量名 来访问一个模块的全局变量。

模块可以导入其他模块。 根据惯例可以将所有 import 语句都放在模块(或者也可以说是脚本)的开头。但这并非强制要求。 如果被放置于一个模块的最高层级,则被导入的模块名称会被添加到该模块的全局命名空间。


还有一种 import 语句的变化形式可以将来自某个模块的名称直接导入到导入方模块的命名空间中。 例如:

1
2
from fibo import fib, fib2
fib(500)

这条语句不会将所导入的模块的名称引入到局部命名空间中(因此在本示例中,fibo 将是未定义的名称)。


还有一种变体可以导入模块内定义的所有名称:

1
2
from fibo import *
fib(500)

这种方式会导入所有不以下划线(_)开头的名称。大多数情况下,不要用这个功能,这种方式向解释器导入了一批未知的名称,可能会覆盖已经定义的名称。

注意,一般情况下,不建议从模块或包内导入 *,因为,这项操作经常让代码变得难以理解。

模块名后使用 as 时,直接把 as 后的名称与导入模块绑定。

1
2
import fibo as fib
fib.fib(500)

import fibo 一样,这种方式也可以有效地导入模块,唯一的区别是,导入的名称是 fib

from 中也可以使用这种方式,效果类似:

1
2
from fibo import fib as fibonacci
fibonacci(500)

备注:

为了保证运行效率,每次解释器会话只导入一次模块。如果更改了模块内容,必须重启解释器;仅交互测试一个模块时,也可以使用 importlib.reload(),例如 import importlib; importlib.reload(modulename),不过不用命令行的话我们应该用不到这个。

12.1.1. 以脚本方式执行模块

可以用以下方式运行 Python 模块:

1
python fibo.py <arguments>

这项操作将执行模块里的代码,和导入模块一样,但会把 __name__ 赋值为 "__main__"。 也就是把下列代码添加到模块末尾:

1
2
3
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))

这个文件既能被用作脚本,又能被用作一个可供导入的模块,因为解析命令行参数的那两行代码只有在模块作为“main”文件执行时才会运行:

1
2
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34

当这个模块被导入到其它模块时,那两行代码不运行:

1
import fibo

这常用于为模块提供一个便捷的用户接口,或用于测试(把模块作为执行测试套件的脚本运行)。

12.1.2. 模块搜索路径

当导入一个名为 spam 的模块时,解释器首先会搜索具有该名称的内置模块。 这些模块的名称在 sys.builtin_module_names 中列出。 如果未找到,它将在变量 sys.path 所给出的目录列表中搜索名为 spam.py 的文件。 sys.path 是从这些位置初始化的:

  • 被命令行直接运行的脚本所在的目录(或未指定文件时的当前目录)。
  • PYTHONPATH(目录列表,与 shell 变量 PATH 的语法一样)。
  • 依赖于安装的默认值(按照惯例包括一个 site-packages 目录,由 site 模块处理)。

更多细节请参阅 sys.path 模块搜索路径的初始化

备注:

在支持符号链接的文件系统中,“被命令行直接运行的脚本所在的目录”是符号链接最终指向的目录。换句话说,符号链接所在的目录并 没有 被添加至模块搜索路径。

初始化后,Python 程序可以更改 sys.path。脚本所在的目录先于标准库所在的路径被搜索。这意味着,脚本所在的目录如果有和标准库同名的文件,那么加载的是该目录里的,而不是标准库的。这一般是一个错误,除非这样的替换是你有意为之。

12.1.3. “已编译的” Python 文件

为了快速加载模块,Python 把模块的编译版本缓存在 __pycache__ 目录中,文件名为 module.*version*.pyc,version 对编译文件格式进行编码,一般是 Python 的版本号。例如,CPython 的 3.3 发行版中,spam.py 的编译版本缓存为 __pycache__/spam.cpython-33.pyc。这种命名惯例让不同 Python 版本编译的模块可以共存。

Python 对比编译版与源码的修改日期,查看编译版是否已过期,是否要重新编译。此进程完全是自动的。此外,编译模块与平台无关,因此,可在不同架构的系统之间共享相同的库。

Python 在两种情况下不检查缓存。一,从命令行直接载入的模块,每次都会重新编译,且不储存编译结果;二,没有源模块,就不会检查缓存。为了让一个库能以隐藏源代码的形式分发(通过将所有源代码变为编译后的版本),编译后的模块必须放在源目录而非缓存目录中,并且源目录绝不能包含同名的未编译的源模块。

给专业人士的一些小建议:

在 Python 命令中使用 -O-OO 开关,可以减小编译模块的大小。-O 去除断言语句,-OO 去除断言语句和 doc 字符串。有些程序可能依赖于这些内容,因此,没有十足的把握,不要使用这两个选项。“优化过的”模块带有 opt- 标签,并且文件通常会一小些。将来的发行版或许会改进优化的效果。

.pyc 文件读取的程序不比从 .py 读取的执行速度快,.pyc 文件只是加载速度更快。

compileall模块可以为一个目录下的所有模块创建 .pyc 文件。

  • 本过程的细节及决策流程图,详见 PEP 3147

12.2. 标准模块

Python 自带一个标准模块的库,它在 Python 库参考(此处以下称为”库参考” )里另外描述。 一些模块是内嵌到解释器里面的, 它们给一些虽并非语言核心但却内嵌的操作提供接口,要么是为了效率,要么是给操作系统基础操作例如系统调入提供接口。 这些模块集是一个配置选项, 并且还依赖于底层的操作系统。 例如,winreg 模块只在 Windows 系统上提供。一个特别值得注意的模块 sys,它被内嵌到每一个 Python 解释器中。sys.ps1sys.ps2 变量定义了一些字符,它们可以用作主提示符和辅助提示符:

1
2
3
4
5
6
import sys
sys.ps1

sys.ps2

sys.ps1 = 'C> '

只有解释器用于交互模式时,才定义这两个变量。

变量 sys.path 是字符串列表,用于确定解释器的模块搜索路径。该变量以环境变量 PYTHONPATH 提取的默认路径进行初始化,如未设置 PYTHONPATH,则使用内置的默认路径。可以用标准列表操作修改该变量:

1
2
import sys
sys.path.append('/ufs/guido/lib/python')

6.3. dir()函数

内置函数 dir()用于查找模块定义的名称。返回结果是经过排序的字符串列表:

1
2
3
4
import fibo, sys
dir(fibo)

dir(sys)

没有参数时,dir()列出当前已定义的名称:

1
2
3
4
a = [1, 2, 3, 4, 5]
import fibo
fib = fibo.fib
dir()

注意它列出所有类型的名称:变量,模块,函数,……。

dir() 不会列出内置函数和变量的名称。这些内容的定义在标准模块 builtins 中:

1
2
import builtins
dir(builtins)

6.4. 包

包是通过使用“带点号模块名”来构造 Python 模块命名空间的一种方式。 例如,模块名 A.B 表示名为 A 的包中名为 B 的子模块。 就像使用模块可以让不同模块的作者不必担心彼此的全局变量名一样,使用带点号模块名也可以让 NumPy 或 Pillow 等多模块包的作者也不必担心彼此的模块名冲突。

假设要为统一处理声音文件与声音数据设计一个模块集(“包”)。声音文件的格式很多(通常以扩展名来识别,例如:.wav.aiff.au),因此,为了不同文件格式之间的转换,需要创建和维护一个不断增长的模块集合。为了实现对声音数据的不同处理(例如,混声、添加回声、均衡器功能、创造人工立体声效果),还要编写无穷无尽的模块流。下面这个分级文件树展示了这个包的架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
sound/                          最高层级的包
__init__.py 初始化 sound 包
formats/ 用于文件格式转换的子包
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ 用于音效的子包
__init__.py
echo.py
surround.py
reverse.py
...
filters/ 用于过滤器的子包
__init__.py
equalizer.py
vocoder.py
karaoke.py
...

导入包时,Python 搜索 sys.path 里的目录,查找包的子目录。

需要有 __init__.py 文件才能让 Python 将包含该文件的目录当作包来处理(除非使用 namespace package,这是一个相对高级的特性)。 这可以防止重名的目录如 string 在无意中屏蔽后继出现在模块搜索路径中的有效模块。 在最简单的情况下,__init__.py 可以只是一个空文件,但它也可以执行包的初始化代码或设置 __all__ 变量,这将在稍后详细描述。

还可以从包中导入单个模块,例如:

1
import sound.effects.echo

这将加载子模块 sound.effects.echo。 它必须通过其全名来引用。

1
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

另一种导入子模块的方法是 :

1
from sound.effects import echo

这也会加载子模块 echo,并使其不必加包前缀,因此可按如下方式使用:

1
echo.echofilter(input, output, delay=0.7, atten=4)

Import 语句的另一种变体是直接导入所需的函数或变量:

1
from sound.effects.echo import echofilter

同样,这将加载子模块 echo,但这使其函数 echofilter() 直接可用:

1
echofilter(input, output, delay=0.7, atten=4)

注意,使用 from package import item 时,item 可以是包的子模块(或子包),也可以是包中定义的函数、类或变量等其他名称。import 语句首先测试包中是否定义了 item;如果未在包中定义,则假定 item 是模块,并尝试加载。如果找不到 item,则触发 ImportError 异常。

相反,使用 import item.subitem.subsubitem 句法时,除最后一项外,每个 item 都必须是包;最后一项可以是模块或包,但不能是上一项中定义的类、函数或变量。

6.4.1. 从包中导入 *

使用 from sound.effects import * 时会发生什么?你可能希望它会查找并导入包的所有子模块,但事实并非如此。因为这将花费很长的时间,并且可能会产生你不想要的副作用,如果这种副作用被你设计为只有在导入某个特定的子模块时才应该发生。

唯一的解决办法是提供包的显式索引。import 语句使用如下惯例:如果包的 __init__.py 代码定义了列表 __all__,运行 from package import * 时,它就是被导入的模块名列表。发布包的新版本时,包的作者应更新此列表。如果包的作者认为没有必要在包中执行导入 * 操作,也可以不提供此列表。例如,sound/effects/__init__.py 文件可以包含以下代码:

1
__all__ = ["echo", "surround", "reverse"]

这意味着 from sound.effects import * 将导入 sound.effects 包的三个命名子模块。

请注意子模块可能会受到本地定义名称的影响。 例如,如果你在 sound/effects/__init__.py 文件中添加了一个 reverse 函数,from sound.effects import * 将只导入 echosurround 这两个子模块,但 不会 导入 reverse 子模块,因为它被本地定义的 reverse 函数所遮挡:

1
2
3
4
5
6
7
8
__all__ = [
"echo", # 指向 'echo.py' 文件
"surround", # 指向 'surround.py' 文件
"reverse", # !!! 现在指向 'reverse' 函数 !!!
]

def reverse(msg: str): # <-- 此名称将覆盖 'reverse.py' 子模块
return msg[::-1] # 针对 'from sound.effects import *' 的情况

如果没有定义 __all__from sound.effects import * 语句 不会 把包 sound.effects 中的所有子模块都导入到当前命名空间;它只是确保包 sound.effects 已被导入(可能还会运行 __init__.py 中的任何初始化代码),然后再导入包中定义的任何名称。 这包括由 __init__.py 定义的任何名称(以及显式加载的子模块)。 它还包括先前 import 语句显式加载的包里的任何子模块。 请看以下代码:

1
2
3
import sound.effects.echo
import sound.effects.surround
from sound.effects import *

在本例中,echosurround 模块被导入到当前命名空间,因为在执行 from...import 语句时它们已在 sound.effects 包中定义了。 (当定义了 __all__ 时也是如此)。

虽然,可以把模块设计为用 import * 时只导出遵循指定模式的名称,但仍不提倡在生产代码中使用这种做法。

记住,使用 from package import specific_submodule 没有任何问题! 实际上,除了导入模块使用不同包的同名子模块之外,这种方式是推荐用法。

6.4.2. 相对导入

当包由多个子包构成(如示例中的 sound 包)时,可以使用绝对导入来引用同级包的子模块。 例如,如果 sound.filters.vocoder 模块需要使用 sound.effects 包中的 echo 模块,它可以使用 from sound.effects import echo

你还可以编写相对导入代码,即使用 from module import name 形式的 import 语句。 这些导入使用前导点号来表示相对导入所涉及的当前包和上级包。 例如对于 surround 模块,可以使用:

1
2
3
from . import echo
from .. import formats
from ..filters import equalizer

注意,相对导入基于当前模块名。因为主模块名永远是 "__main__" ,所以如果计划将一个模块用作 Python 应用程序的主模块,那么该模块内的导入语句必须始终使用绝对导入。

6.4.3. 多目录中的包

包还支持一个特殊的属性, __path__ 。 在执行该文件中的代码之前,它被初始化为字符串的 sequence,其中包含包的 __init__.py 的目录名称。这个变量可以修改;修改后会影响今后对模块和包中包含的子包的搜索。

这个功能虽然不常用,但可用于扩展包中的模块集。

十三、作用域

Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:

1
2
3
4
5
6
>>> if True:
... msg = 'I am from Runoob'
...
>>> msg
'I am from Runoob'
>>>

实例中 msg 变量定义在 if 语句块中,但外部还是可以访问的。

如果将 msg 定义在函数中,则它就是局部变量,外部不能访问:

1
2
3
4
5
6
7
8
>>> def test():
... msg_inner = 'I am from Runoob'
...
>>> msg_inner
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'msg_inner' is not defined
>>>

从报错的信息上看,说明了 msg_inner 未定义,无法使用,因为它是局部变量,只有在函数内可以使用。

全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/python3

total = 0 # 这是一个全局变量
# 可写函数说明
def sum( arg1, arg2 ):
#返回2个参数的和."
total = arg1 + arg2 # total在这里是局部变量.
print ("函数内是局部变量 : ", total)
return total

#调用sum函数
sum( 10, 20 )
print ("函数外是全局变量 : ", total)

以上实例输出结果:

1
2
函数内是局部变量 :  30
函数外是全局变量 : 0

global 和 nonlocal关键字

当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。

以下实例修改全局变量 num:

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/python3

num = 1
def fun1():
global num # 需要使用 global 关键字声明
print(num)
num = 123
print(num)
fun1()
print(num)

以上实例输出结果:

1
2
3
1
123
123

如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了,如下实例:

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()

以上实例输出结果:

1
2
100
100

另外有一种特殊情况,假设下面这段代码被运行:

1
2
3
4
5
6
7
#!/usr/bin/python3

a = 10
def test():
a = a + 1
print(a)
test()

以上程序执行,报错信息如下:

1
2
3
4
5
6
Traceback (most recent call last):
File "test.py", line 7, in <module>
test()
File "test.py", line 5, in test
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

错误信息为局部作用域引用错误,因为 test 函数中的 a 使用的是局部,未定义,无法修改。

修改 a 为全局变量:

1
2
3
4
5
6
7
8
#!/usr/bin/python3

a = 10
def test():
global a
a = a + 1
print(a)
test()

执行输出结果为:

1
11

也可以通过函数参数传递:

1
2
3
4
5
6
7
#!/usr/bin/python3

a = 10
def test(a):
a = a + 1
print(a)
test(a)

执行输出结果为:

1
11

十四、日期处理

datetime 模块为日期和时间处理同时提供了简单和复杂的方法。

支持日期和时间算法的同时,实现的重点放在更有效的处理和格式化输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
import datetime

#获取当前日期和时间
current_datetime = datetime.datetime.now()
print(current_datetime)

# 获取当前日期
current_date = datetime.date.today()
print(current_date)

# 格式化日期
formatted_datetime = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
print(formatted_datetime)

输出结果为:

1
2
3
2024-11-16 21:15:34.808260
2024-11-16
2024-11-16 21:15:34

该模块还支持时区处理:

1
2
3
4
5
6
7
8
9
10
11
12
# 导入了 datetime 模块中的 date 类
from datetime import date
now = date.today() # 当前日期
print(now)
datetime.date(2023, 7, 17)
print(now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B."))


# 创建了一个表示生日的日期对象
birthday = date(1964, 7, 31)
age = now - birthday # 计算两个日期之间的时间差
print(age.days) # 变量age的days属性,表示时间差的天数

来写一个能计算今天距离考试时间还有多少天的小程序试试看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import datetime as dt
now = dt.date.today()
print("请输入截止日期:(格式:年 月 日)")
while True:
try:
year,month,day = map(int,input().split())
ddl = dt.date(year,month,day)
if(ddl < now):
print("输入的日期不能早于今天")
continue
break
except ValueError:
print("输入的不是正确的日期")
continue
except Exception as e:
print("发生错误:{e}")


result = ddl - now
print(f'距离 {ddl.strftime("%Y年%m月%d日")}还有{result.days}天')

Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串

语法

split() 方法语法:

1
>>str.split(str="", num=string.count(str))

参数

  • str – 分隔符,不手动指定的话,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。(写str=或者直接上字符串都行,这是python的特性),
  • num – 分割次数。默认为 -1, 即分隔所有。

返回值

返回分割后的字符串列表。

map() 会根据提供的函数对指定序列做映射。

第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

也就是用function函数处理后面给的序列里面的每一个元素,然后返回处理后的所有元素

map() 函数语法:

1
>>map(function, iterable, ...)

参数

  • function – 函数
  • iterable – 一个或多个序列

当我们执行 ddl - now 时,datetime.date 类通过重载减法运算符 __sub__ 来实现两个日期对象的减法,返回一个 timedelta 对象。

result 是 datetime.timedelta 类型,它表示两个日期之间的时间差。

timedelta 类的主要属性:

​ days: 天数

​ seconds: 秒数(不包括天数)

​ microseconds: 微秒数

Python time strftime() 函数用于格式化时间,返回以可读字符串表示的当地时间,格式由参数 format 决定。

语法

strftime()方法语法:

1
>>time.strftime(format[, t])

参数

  • format – 格式字符串。
  • t – 可选的参数 t 是一个 struct_time 对象。

返回值

返回以可读字符串表示的当地时间。

说明

python中时间日期格式化符号:

  • %y 两位数的年份表示(00-99)
  • %Y 四位数的年份表示(000-9999)
  • %m 月份(01-12)
  • %d 月内中的一天(0-31)
  • %H 24小时制小时数(0-23)
  • %I 12小时制小时数(01-12)
  • %M 分钟数(00=59)
  • %S 秒(00-59)
  • %a 本地简化星期名称
  • %A 本地完整星期名称
  • %b 本地简化的月份名称
  • %B 本地完整的月份名称
  • %c 本地相应的日期表示和时间表示
  • %j 年内的一天(001-366)
  • %p 本地A.M.或P.M.的等价符
  • %U 一年中的星期数(00-53)星期天为星期的开始
  • %w 星期(0-6),星期天为星期的开始
  • %W 一年中的星期数(00-53)星期一为星期的开始
  • %x 本地相应的日期表示
  • %X 本地相应的时间表示
  • %Z 当前时区的名称
  • %% %号本身

实例

以下实例展示了 strftime() 函数的使用方法:

1
2
>>#!/usr/bin/python
>># -*- coding: UTF-8 -*-

通过导入 future 包来兼容 Python3.x print

如果使用了 Python3.x 可以删除此行引入

from future import print_function

from datetime import datetime

now = datetime.now() # current date and time

year = now.strftime(“%Y”)
print(“year:”, year)

month = now.strftime(“%m”)
print(“month:”, month)

day = now.strftime(“%d”)
print(“day:”, day)

time = now.strftime(“%H:%M:%S”)
print(“time:”, time)

date_time = now.strftime(“%Y-%m-%d, %H:%M:%S”)
print(“date and time:”,date_time)

1

以上实例输出结果为:

1
2
3
4
5
>>year: 2024
>>month: 11
>>day: 16
>>time: 21:25:22
>>date and time: 2024-11-16, 21:25:22

::warning:

(待补充)

十九、随笔

1.获取字符串中数字

1
2
3
4
from curses.ascii import isdigit

def GetDigit(str1):
return ''.join([digit1 for digit1 in str1 if isdigit(digit1)])

join 是 Python 字符串的一个方法,用于将可迭代对象(如列表、元组等)中的元素连接成一个字符串。它使用调用该方法的字符串作为分隔符。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用空字符串作为分隔符

list_of_strings = ['a', 'b', 'c']

result = ''.join(list_of_strings)

print(result) # 输出: "abc"

# 使用逗号作为分隔符

result_with_comma = ','.join(list_of_strings)

print(result_with_comma) # 输出: "a,b,c"

2.Counter类

Counter 类是 Python collections 模块中的一个有用的工具,用于计数可哈希对象。它是 dict 的子类,专门用于计数对象的出现次数。

1.创建Counter对象

可以通过多种方式创建 Counter 对象:

  1. 直接传入一个可迭代对象(如字符串、列表等)。
  2. 传入一个字典,其中键是要计数的对象,值是它们的计数。
  3. 使用关键字参数传入对象及其计数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 通过字符串创建 Counter 对象
counter1 = Counter("hello world")
print(counter1) # 输出: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})

# 通过列表创建 Counter 对象
counter2 = Counter(['a', 'b', 'c', 'a', 'b', 'b'])
print(counter2) # 输出: Counter({'b': 3, 'a': 2, 'c': 1})

# 通过字典创建 Counter 对象
counter3 = Counter({'a': 2, 'b': 3, 'c': 1})
print(counter3) # 输出: Counter({'b': 3, 'a': 2, 'c': 1})

# 通过关键字参数创建 Counter 对象
counter4 = Counter(a=2, b=3, c=1)
print(counter4) # 输出: Counter({'b': 3, 'a': 2, 'c': 1})

常用方法和操作

  1. 元素计数:可以像访问字典一样访问 Counter 对象中的元素计数。

    1
    print(counter1['l']) # 输出: 3
  2. 更新计数:使用 update 方法更新计数。

    1
    2
    3
    counter1.update("hello")

    print(counter1) # 输出: Counter({'l': 5, 'o': 3, 'h': 2, 'e': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
  3. 减去计数:使用 subtract 方法减去计数。

    1
    2
    3
    counter1.subtract("hello")

    print(counter1) # 输出: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
  4. 获取最常见的元素:使用 most_common 方法获取最常见的元素及其计数。

    1
    print(counter1.most_common(2)) # 输出: [('l', 3), ('o', 2)]
  5. 元素列表:使用 elements 方法返回一个迭代器,包含 Counter 对象中的所有元素。

    1
    print(list(counter1.elements())) # 输出: ['h', 'e', 'l', 'l', 'l', 'o', 'o', ' ', 'w', 'r', 'd']

3.字符串去重

1.倒序遍历字符串

  1. 使用切片

    1
    2
    3
    s = "hello"
    for char in s[::-1]:
    print(char)
  2. 使用reversed函数

    reversed 函数返回一个反向迭代器,可以用于遍历字符串。

    1
    2
    3
    s = "hello"
    for char in reversed(s):
    print(char)
  3. 使用索引

    1
    2
    3
    s = "hello"
    for i in range(len(s) - 1, -1, -1):
    print(s[i])

2.切片

切片(Slicing)是一种强大的工具,用于从序列(如字符串、列表、元组等)中提取子序列。切片通过指定起始位置、结束位置和步长来创建一个新的子序列。

  1. 基本语法

    1
    sequence[start:stop:step]
    • start:切片开始的位置(包含)。
    • stop:切片结束的位置(不包含)。
    • step:切片的步长(默认为1)。
  2. 字符串切片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    s = "hello world"

    # 提取子字符串 "hello"
    print(s[0:5]) # 输出: "hello"

    # 提取子字符串 "world"
    print(s[6:11]) # 输出: "world"

    # 从头到尾提取整个字符串
    print(s[:]) # 输出: "hello world"

    # 从索引 6 开始提取到结尾
    print(s[6:]) # 输出: "world"

    # 从头开始提取到索引 5(不包含)
    print(s[:5]) # 输出: "hello"

    # 每隔一个字符提取一次
    print(s[::2]) # 输出: "hlowrd"

    # 反向提取整个字符串
    print(s[::-1]) # 输出: "dlrow olleh"
  3. 列表切片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    # 提取子列表 [2, 3, 4]
    print(lst[2:5]) # 输出: [2, 3, 4]

    # 从索引 5 开始提取到结尾
    print(lst[5:]) # 输出: [5, 6, 7, 8, 9]

    # 从头开始提取到索引 5(不包含)
    print(lst[:5]) # 输出: [0, 1, 2, 3, 4]

    # 每隔一个元素提取一次
    print(lst[::2]) # 输出: [0, 2, 4, 6, 8]

    # 反向提取整个列表
    print(lst[::-1]) # 输出: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
  4. 应用:

    • 去掉字符串中某个字符

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      def remove_char_at(s, index):
      if index < 0 or index >= len(s):
      raise ValueError("Index out of range")
      return s[:index] + s[index+1:]

      # 示例
      input_string = "hello world"
      index_to_remove = 5
      result = remove_char_at(input_string, index_to_remove)
      print(result) # 输出: "helloworld"
    • 倒序遍历字符串

      1
      2
      3
      s = "hello"
      for char in s[::-1]:
      print(char)

3.去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from collections import Counter

def distinct(str3):
str3_lower = str3.lower()
counter2 = Counter(str3_lower)
result = list(str3)
for i in range(len(str3) - 1, -1, -1):
if counter2[str3_lower[i]] >= 2:
counter2[str3_lower[i]] -= 1
result.pop(i)
print(''.join(result)) # 打印最终的字符串结果

str11 = input()
distinct(str11)

Q&A:return ‘’.join(result)换成print(str(result))不行吗,为什么我打印出来了个列表一样的东西

result是一个字符列表,使用 ''.join(result) 可以将列表中的字符连接成一个字符串。

4.修改字符串

字符串不可变,一般将字符串转换为列表,然后使用pop方法删除特定位置的字符,之后再将列表转换回字符串

5.排序

sorted() 函数对所有可迭代的对象进行排序操作。

sort 与 sorted 区别:

sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。

list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。

语法

sorted 语法:

1
sorted(iterable, cmp=None, key=None, reverse=False)

参数说明:

  • iterable – 可迭代对象。
  • cmp – 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
  • key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse – 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

注:长得有点像c语言的qsort呢

Python3已经移除了cmp

因为对于n个元素的序列,key函数只需要调用n次,cmp函数可能需要调用nlog(n)次,

非要用的话python3给了functools.cmp_to_key

1
2
3
4
5
6
7
8
9
10
from functools import cmp_to_key

L = [('b',2), ('a',1), ('c',3), ('d',4)]

# 老式的 cmp 写法转换成新式的 key 写法
def my_cmp(x, y):
return x[1] - y[1]

# 使用 cmp_to_key 转换
result = sorted(L, key=cmp_to_key(my_cmp))

返回值

返回重新排序的列表。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
#
a = [9,8,6,1,2,3,4,5,7]
b = sorted(a)
# 按字符串中字符出现频率从高到低输出到列表,忽略大小写,如果次数相同则按字母顺序排列。
from collections import counter
def sortByFrequency(str1):
str1_lower = str1.lower()
counter1 = Counter(str1_lower)
result = sorted(counter1.items(), key=lambda x: (-x[1], x[0]))
#默认是升序排列,但是我们的两个排序规则是相反的,频率降序,字母本身又是升序,所以取频率的相反数来降序排序,就是按频率升序

print(result)

为什么用counter1.items()而不是counter1?
counter是一个字典,想访问值必须通过每个键,而使用了items之后得到的是一个列表,其中每个元素都是一个元组,元组内两个元素分别是原来的键和值

1
2
counter = Counter("hello")
print(counter) # 输出:Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
1
2
3
items = counter.items()
print(list(items)) # 输出:[('h', 1), ('e', 1), ('l', 2), ('o', 1)]
# 每个元素都是一个元组:(字符, 出现次数)

6.便捷地交换两个变量的值

1
2
if num1 < num2:
num1,num2 = num2,num1

7.循环的技巧

(1)items()

当对字典执行循环时,可以使用 items() 方法同时提取键及其对应的值。

1
2
3
4
5
6
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
print(k, v)

#gallahad the pure
#robin the brave

(2)enumerate()

在序列中循环时,用 enumerate()函数可以同时取出位置索引和对应的值:

1
2
3
4
5
6
7
8
9
10
students = {'han':'naseele', 'ljq':'smalldog','ljc':'loli','dogxi':'vr'}
for i,j in enumerate(students):
print(i,j,students[j])

'''
0 han naseele
1 ljq smalldog
2 ljc loli
3 dogxi vr
'''

(3)zip()

同时循环两个或多个序列时,用 zip()函数可以将其内的元素一一匹配:

1
2
3
4
5
6
7
8
questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
print('What is your {0}? It is {1}.'.format(q, a))

#What is your name? It is lancelot.
#What is your quest? It is the holy grail.
#What is your favorite color? It is blue.
::warning::

{1} 是格式化占位符,当只传入一个参数时,应该使用 {0} 来引用第一个(也是唯一的)参数,例如:

1
2
3
4
5
6
questions = ["name","gender","age","habit","phone_number","address"]
answers = ["naseele","女","19","play piano","1145141515810","Solar-6"]

for q,a in zip(questions,answers):
print("What is your {0}?".format(q))
print("It's {0}".format(a))

其实还可以这样:

1
2
for q,a in zip(questions,answers):
print(f"What is your {q}?\nIt's {a}")

(4)reversed()

为了逆向对序列进行循环,可以求出欲循环的正向序列,然后调用 reversed()` 函数:

1
2
3
4
5
6
7
8
for i in reversed(range(1, 10, 2)):
print(i)

#9
#7
#5
#3
#1

(5)sorted()

按指定顺序循环序列,可以用 sorted()函数,在不改动原序列的基础上,返回一个重新的序列:

1
2
3
4
5
6
7
8
9
10
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for i in sorted(basket):
print(i)

#apple
#apple
#banana
#orange
#orange
#pear

(6)set()

使用 set()去除序列中的重复元素。使用 sorted()set() 则按排序后的顺序,循环遍历序列中的唯一元素:

1
2
3
4
5
6
7
8
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for f in sorted(set(basket)):
print(f)

#apple
#banana
#orange
#pear

(7)

一般来说,在循环中修改列表的内容时,创建新列表比较简单,且安全:

1
2
3
4
5
6
7
8
9
import math
raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
filtered_data = []
for value in raw_data:
if not math.isnan(value):
filtered_data.append(value)

print(filtered_data)
#[56.2, 51.7, 55.3, 52.5, 47.8]

8. 深入条件控制

whileif 条件句不只可以进行比较,还可以使用任意运算符。

比较运算符 innot in 用于执行确定一个值是否存在(或不存在)于某个容器中的成员检测。 运算符 isis not 用于比较两个对象是否是同一个对象。 所有比较运算符的优先级都一样,且低于任何数值运算符。

比较操作支持链式操作。例如,a < b == c 校验 a 是否小于 b,且 b 是否等于 c

1
2
3
4
5
6
7
8
9
10
11
12
13
a = 55
b = 77
c = 88
if (a < b == c) == a < b and b == c :
print("对啦")
else:
print("错误的")
#错误的
if (a < b == c) == (a < b and b == c) :
print("对啦")
else:
print("错误的")
#对啦
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'''为什么看似一样的两个if语句结果不一样呢

第一个if语句:
这个表达式会按照以下顺序执行:
首先计算 a < b == c:
a < b 为 True(55 < 77)
b == c 为 False(77 ≠ 88)
所以 a < b == c 整体为 False
然后计算右边:
a < b 为 True
b == c 为 False
最终变成:False == True and False,结果为 False

第二个if语句:
这个表达式是在比较两个完整的布尔表达式:
左边 (a < b == c) 为 False
右边 (a < b and b == c) 也为 False
所以 False == False 为 True
'''

比较操作可以用布尔运算符 andor 组合,并且,比较操作(或其他布尔运算)的结果都可以用 not 取反。这些操作符的优先级低于比较操作符;not 的优先级最高, or 的优先级最低,因此,A and not B or C 等价于 (A and (not B)) or C。与其他运算符操作一样,此处也可以用圆括号表示想要的组合。

布尔运算符 andor 是所谓的 短路 运算符:其参数从左至右求值,一旦可以确定结果,求值就会停止。例如,如果 AC 为真,B 为假,那么 A and B and C 不会对 C 求值。用作普通值而不是布尔值时,短路运算符的返回值通常是最后一个求了值的参数。

还可以把比较运算或其它布尔表达式的结果赋值给变量,例如:

1
2
3
4
string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
non_null = string1 or string2 or string3
print(non_null)
#'Trondheim'

注意,Python 与 C 不同,在表达式内部赋值必须显式使用 海象运算符 :=。 这避免了 C 程序中常见的问题:要在表达式中写 == 时,却写成了 =

9.->

在Python中,-> 是函数注解(Function Annotation)的语法,用于指示函数的返回值类型。

1
2
3
4
5
6
7
8
def get_name() -> str:  # 表示这个函数会返回字符串
return "张三"

def get_age() -> int: # 表示这个函数会返回整数
return 18

def process_data(x: int) -> list: # 表示接收整数参数,返回列表
return [x]

print((1,5)==(5,1)) 不相等