Python基础知识点

 

一、数据类型

1.0、数字

浮点数
保留小数位数
# 用round实现,返回的是float round(f, n) # f是浮点数,n是需要保留的位数 # 用占位符实现,返回的是str f_num = float(input()) print(f'{f_num:.2f}') # .2f中的2表示小数位数,可以更改;f代表要操作的float print('%.2f' % f_num) print('{:.2f}'.format(f_num))
 
# python取整 int(-0.8) # 取整数部分 round(-0.4) # 四舍五入 math.floor(-0.8) # 向下取整 math.ceil(-0.8) # 向上取整
 
进制转换
非10进制之间的转换需要借助10进制中转
int(str, 2) # 2转10,输入字符串,返回数字 int(str, 8) # 8转10,输入字符串,返回数字 int(str, 16) # 16转10,输入字符串,返回数字 bin(num) # 10转2,输入数字,返回字符串 oct(num) # 10转8,输入数字,返回字符串 hex(num) # 10转16,输入数字,返回字符串
 

运算符

算术运算

运算符
描述
实例:a=10,b=21
备注
+
加 - 两个对象相加
a + b 输出结果 31
-
减 - 得到负数或是一个数减去另一个数
a - b 输出结果 -11
*
乘 - 两个数相乘或是返回一个被重复若干次的字符串
a * b 输出结果 210
**
幂 - 返回x的y次幂
a**b 为10的21次方
/
除 - x 除以 y
b / a 输出结果 2.1
不管式子中的是int还是flot,结果返回小数
%
取模 - 返回除法的余数
b % a 输出结果 1
式子中都为int时返回int型;式子中有flot时返回flot型
//
取整除 - 向下取整
>>> 9//2 4 >>> -9//2 -5
式子中都为int时返回int型;式子中有flot时返回flot型

赋值运算

运算符
描述
实例
=
简单的赋值运算符
c = a + b 将 a + b 的运算结果赋值为 c
+=
加法赋值运算符
c += a 等效于 c = c + a
-=
减法赋值运算符
c -= a 等效于 c = c - a
*=
乘法赋值运算符
c *= a 等效于 c = c * a
/=
除法赋值运算符
c /= a 等效于 c = c / a
%=
取模赋值运算符
c %= a 等效于 c = c % a
**=
幂赋值运算符
c **= a 等效于 c = c ** a
//=
取整除赋值运算符
c //= a 等效于 c = c // a
:=
海象运算符(在循环或条件语句中赋值使用,被赋值的变量在之后的代码块中可以继续使用)详细教程 python 3.8 之后才有
if count := fresh_fruit.get('lemon', 0): if (count := fresh_fruit.get('lemon', 0)) >= 3: dic, scor, count = {'A':4, 'B':3, 'C':2, 'D':1, 'F':0}, 0, 0 while (gpa := dic.get(input(), False)) is not False: s = int(input()) scor, count = scor + s * gpa, count + gpa print(f'{(scor/count):.2f}') while (n := n - 1) + 1:
while (n := n - 1) + 1:

逻辑运算

运算符
含义
逻辑表达式
描述
实例:a=10,b=21
and
x and y
如果左边为假,整体判断为假,将左边的值作为输出 如果左边为真,不管整体真假,将右边的值作为输出
(a and b) 返回 21
or
x or y
如果左边为真,整体判断为真,将左边的值作为输出 如果左边为假,不管整体真假,将右边的值作为输出
(a or b) 返回 10
not
not x
如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。
not(a and b) 返回 False

位运算

💡
数字是以“补码”的形式存储在计算机中的,位运算也是用“补码”进行计算。
  • 原码:我们将数字的二进制表示的最高位视为符号位,其中0表示正数1表示负数,其余位表示数字的值。
  • 反码:正数的反码与其原码相同,负数的反码是对其原码除符号位外的所有位取反。
  • 补码:正数的补码与其原码相同,负数的补码是在其反码的基础上加 1。
notion imagenotion image
 
运算符
含义
描述
实例:a=9, b=5
运算细则
&
按位与运算
两个数的二进制,相同位置都为1,结果为1,否则为0
9 & 5
0000 1001 (9 的补码) 0000 0101 (5 的补码) ----------------------- 0000 0001 (1 的补码)
|
按位或运算
两个数的二进制,相同位置都为0,结果为0,否则为1
9 | 5
0000 1001 (9 的补码) 0000 0101 (5 的补码) ----------------------- 0000 1101 (13 的补码)
^
按位异或运算
两个数的二进制,相同位置值不同,结果为1,否则为0
9 ^ 5
0000 1001 (9 的补码) 0000 0101 (5 的补码) ----------------------- 0000 1100 (12 的补码)
~
按位取反运算
单目运算,对二进制取反
~9
0000 1001 (9 的补码) ----------------------- 1111 0110 (-10 的补码)
<<
按位左移运算
单目运算,对二进制左移若干位,由 << 右边的数字指定了移动的位数;高位丢弃,低位补0。
9<<3
0000 1001 (9 的补码) ----------------------- 0100 1000 (72 的补码)
>>
按位右移运算
单目运算,对二进制右移若干位,由 << 左边的数字指定了移动的位数;低位丢弃,高位补 0 或 1(根据高维的值决定)
9>>3
0000 1001 (9 的补码) ----------------------- 0000 0001 (1 的补码)
-9>>3
1111 0111 (-9 的补码) ---------------------- 1111 1110 (-2 的补码)

1.1、字符串

  • 可以在字符串中使用\(反斜杠)来表示转义,也就是说\后面的字符不再是它原来的意义,例如:\n不是代表反斜杠和字符n,而是表示换行;而\t也不是代表反斜杠和字符t,而是表示制表符。所以如果想在字符串中表示'要写成\',同理想表示\要写成\\
  • 如果不希望字符串中的\表示转义,我们可以通过在字符串的最前面加上字母r来加以说明,如:s1 = r'\'hello, world!\'' 前缀 r 和 f 可以一起使用。
    • f-strings的其他用法:Python--字符串格式化f-string
    • 此外,如果字符串是一个文件路径,且路径中包含空格,那么可能不能被 Python 识别,此时在字符串前加 r 来阻止转义即可。
  • Python为字符串类型提供了非常丰富的运算符,我们可以使用+运算符来实现字符串的拼接,可以使用*运算符来重复一个字符串的内容,可使用innot in来判断一个字符串是否包含另外一个字符串(成员运算),我们也可以用[][:]运算符从字符串取出某个字符或某些字符(切片运算)
  • 格式化输出字符串:占位符
    • a, b = 5, 10
    • print(f'{a} * {b} = {a * b}') python3.6之后的写法
    • print('%d * %d = %d' % (a, b, a * b))
    • print('{0} * {1} = {2}'.format(a, b, a * b))
  • 在Python中,我们还可以通过一系列的方法来完成对字符串的处理:
    • str1 = 'hello, world!' print(len(str1)) # 13 # 通过内置函数len计算字符串的长度 print(str1.capitalize()) # Hello, world! # 获得字符串首字母大写的拷贝 print(str1.title()) # Hello, World! # 获得字符串每个单词首字母大写的拷贝 print(str1.upper()) # HELLO, WORLD! # 获得字符串变大写后的拷贝 print(str1.find('or')) # 8 # 从字符串中查找子串所在位置,找不到返回-1 print(str1.find('shit')) # -1 print(str1.index('or')) # 与find类似但找不到子串时会引发异常 print(str1.index('shit')) # ValueError: substring not found print(str1.startswith('He')) # False # 检查字符串是否以指定的字符串开头,会区分大小写 print(str1.startswith('hel')) # True print(str1.endswith('!')) # True # 检查字符串是否以指定的字符串结尾 print(str1.center(50, '*')) # 将字符串以指定的宽度居中并在两侧填充指定的字符 print(str1.rjust(50, ' ')) # 将字符串以指定的宽度靠右放置左侧填充指定的字符 str2 = 'abc123456' print(str2.isdigit()) # False # 检查字符串是否只由数字构成 print(str2.isalpha()) # False # 检查字符串是否只以字母构成 print(str2.isalnum()) # True # 检查字符串是否以数字和字母构成 str3 = ' Jackfrued@126.com ' print(str3.strip()) # 修剪字符串两端的指定字符,默认是空格 print(str3.split()) # 按照指定字符切割字符串,python内置的函数只能使用单个分隔符 re.split(r'。|!|?','字符串1。文本?') # 用re模块可以一次使用多个分隔符 print(str3.lower()) # 转换字符串中所有大写字符为小写 print(str3.upper()) # 转换字符串中的小写字母为大写 print(str3.title()) # 首字母大写,如果有空格,则对每个空格后的单词首字母大写 print(str3.capitalize()) # 首字母大写,只会对整个字符串的首字母大写,即使有空格 print(str3.swapcase()) # 将字符串中大写转换为小写,小写转换为大写 print(str3.lstrip()) # 截掉字符串左边的空格或指定字符 print(str3.rstrip()) # 删除字符串末尾的空格或指定字符 print(str3.replace(old, new [, max])) # 将字符串中的old替换成new, 如果max指定,则替换不超过max次。 seq = '_'.join(seq) # 以指定字符串作为分隔符,将seq中所有的元素(的字符串表示)合并为一个新的字符串 # 占位符可以和以上方法一起使用 ['subject_%s'%i.lower() for i in data_.columns]
  • maketrans()方法:用于创建字符映射的转换表
    • translation_table = str.maketrans(x, y, z) # x:必选;原有的需要替换的字符, 如果只有 x,那 x 必须是一个字典 # y:可选;想要替换成的目标字符,y 的长度一定要和 x 相同 # z:可选;原字符串中想要删除的字符, 是先删除,后替换;如果只想删除某些字符,可以让 x 和 y 为空。 str5.translate(translation_table) # 示例 str5 = "Google Runoob Taobao!" translation_table = str.maketrans("mSa", "eJo", "odnght") str5.translate(translation_table) """ 'Gle Rub Tobo!' """
  • eval() 方法:将字符串转换为相应的对象,并返回表达式的结果(把字符串去掉,并运行
    • result = eval("2 + 3 * 4") print(result) # 输出: 14 # 执行变量引用 x = 10 result = eval("x + 5") print(result) # 输出: 15 # 在指定命名空间中执行表达式 namespace = {'a': 2, 'b': 3} result = eval("a + b", namespace) print(result) # 输出: 5 # 如果字符串内是列表,则直接返回列表 str1 = "[1,2,3]" list1 = eval(str1)

1.2、列表

  • 列表(list),也是一种结构化的、非标量类型,它是值的有序序列,每个值都可以通过索引进行标识,定义列表可以将列表的元素放在[]中,多个元素用,进行分隔,可以使用for循环对列表元素进行遍历,也可以使用[][:]运算符取出列表中的一个或多个元素。
  • 列表生成式:
    • f = [x for x in range(1, 10)]
    • f = [x*2 for x in range(1, 10) if x>5]
    • f = [x*2 if x>5 else x for x in range(1, 10)]
    • f = [x + y for x in 'ABCDE' for y in '1234567']
    • f = [(name, sex) for name, sex in zip(list1, list2)]
list1 = [1, 3, 5, 7, 100] # 增 print(list1.append(200)) # 在列表的最后追加元素;[1, 3, 5, 7, 100, 200] print(list1.insert(1, 400)) # 在索引1的位置插入元素;[1, 400, 3, 5, 7, 100, 200] print(list1.extend([8,9,11])) # 函数用于在列表末尾一次性追加另一个序列中的多个值;[1, 400, 3, 5, 7, 100, 200, 8,9,11] # 删 del list1[2] # 删除指定索引的元素 print(list1) # [1, 400, 5, 7, 100, 200] list1.remove(5) # 移除列表中某个值的第一个匹配项 print(list1) # [1, 400, 7, 100, 200] print(list1.pop()) # 200 # 移除列表中的一个元素(默认最后一个元素), 并且返回该元素的值, 可以指定索引 # 查 print(list1[3]) # 100 # 取索引为3的元素 print(list1[-1]) # 100 # 取最后一个元素 print(list1[1:3]) # [400, 7] # 取一个区间(前开后闭:能取到1不能取到3) # 改 list1[1] = 'value' # 赋值 print(list1) # [1, 'value', 7, 100, 200] # 其他方法 list(seq) # 将其他seq转换为列表 len(list1) # 列表长度 min(list1) # 列表最小值 max(list1) # 列表最大值 list1.count(obj) # 统计某个元素在列表中出现的次数 list1.index(obj) # 从列表中找出某个值第一个匹配项的索引位置 list1.reverse() # 反转列表 list1.clear() # 清空列表元素 list1.sort(reverse=True) # 排序——直接在原列表上进行排序 list1 += [1000, 2000] # 合并两个列表 # 排序——不会修改原列表,返回新列表 list1 = ['orange', 'apple', 'zoo', 'internationalization', 'blueberry'] list2 = sorted(list1) # 根据首字母在字母表中的位置升序 print(list2) # ['apple', 'blueberry', 'internationalization', 'orange', 'zoo'] list3 = sorted(list1, reverse=True) # 根据首字母在字母表中的位置倒序 print(list3) # ['zoo', 'orange', 'internationalization', 'blueberry', 'apple'] list4 = sorted(list1, key=len) # 根据元素长度升序 print(list4) # ['zoo', 'apple', 'orange', 'blueberry', 'internationalization'] # 列表反转 # 方法0:list1.reverse() # 方法1:list(reversed(a)),reversed(a)返回的是迭代器,所以前面加个list转换为list # 方法2:sorted(a,reverse=True) # 方法3:a[: :-1],其中[::-1]代表从后向前取值,每次步进值为1 # b = a[i:j:s];i是起点,j是终点,s是步长 # 当s<0,且i缺省时,则a默认为-1. # 当s<0,且j缺省时,默认为-len(a)-1 # 所以a[::-1]相当于 a[-1:-len(a)-1:-1],也就是从最后一个元素到第一个元素复制一遍,即倒序。

1.3、元组

Python中的元组与列表类似也是一种容器数据类型,可以用一个变量(对象)来存储多个数据,不同之处在于元组的元素不能修改
这里有一个非常值得探讨的问题,我们已经有了列表这种数据结构,为什么还需要元组这样的类型呢?
  1. 元组中的元素是无法修改的,事实上我们在项目中尤其是多线程环境(后面会讲到)中可能更喜欢使用的是那些不变对象(一方面因为对象状态不能修改,所以可以避免由此引起的不必要的程序错误,简单的说就是一个不变的对象要比可变的对象更加容易维护;另一方面因为没有任何一个线程能够修改不变对象的内部状态,一个不变对象自动就是线程安全的,这样就可以省掉处理同步化的开销。一个不变对象可以方便的被共享访问)。所以结论就是:如果不需要对元素进行添加、删除、修改的时候,可以考虑使用元组,当然如果一个方法要返回多个值,使用元组也是不错的选择。
  1. 元组在创建时间和占用的空间上面都优于列表。我们可以使用sys模块的getsizeof函数来检查存储同样的元素的元组和列表各自占用了多少内存空间,这个很容易做到。我们也可以在ipython中使用魔法指令%timeit来分析创建同样内容的元组和列表所花费的时间,

1.4、集合

Python中的集合跟数学上的集合是一致的,不允许有重复元素,而且可以进行交集、并集、差集、补集等运算。
notion imagenotion image
# 创建集合的字面量语法 set1 = {1, 2, 3, 3, 3, 2} print(set1) print('Length =', len(set1)) # 创建集合的构造器语法(面向对象部分会进行详细讲解) set2 = set(range(1, 10)) set3 = set((1, 2, 3, 3, 2, 1)) print(set2, set3) # 创建集合的推导式语法(推导式也可以用于推导集合) set4 = {num for num in range(1, 100) if num % 3 == 0 or num % 5 == 0} print(set4) set1.add(4) set1.add(5) set2.update([11, 12]) set2.discard(5) if 4 in set2: set2.remove(4) print(set1, set2) print(set3.pop()) print(set3) # 集合的交集、并集、差集、对称差运算 print(set1 & set2) # print(set1.intersection(set2)) print(set1 | set2) # print(set1.union(set2)) print(set1 - set2) # print(set1.difference(set2)) print(set1 ^ set2) # print(set1.symmetric_difference(set2)) # 判断子集和超集 print(set2 <= set1) # print(set2.issubset(set1)) print(set3 <= set1) # print(set3.issubset(set1)) print(set1 >= set2) # print(set1.issuperset(set2)) print(set1 >= set3) # print(set1.issuperset(set3)) .argsort() # 返回数组值从小到大的索引值 [::-1] # 倒序取值

1.5、字典

Python中的字典跟我们生活中使用的字典是一样一样的,它可以存储任意类型对象,与列表、集合不同的是,字典的每个元素都是由一个键和一个值组成的“键值对”,键和值通过冒号分开。
# 创建字典的字面量语法 scores = {'骆昊': 95, '白元芳': 78, '狄仁杰': 82} print(scores) # 创建字典的构造器语法 items1 = dict(one=1, two=2, three=3, four=4) # 通过zip函数将两个序列压成字典 items2 = dict(zip(['a', 'b', 'c'], '123')) # 创建字典的推导式语法 items3 = {num: num ** 2 for num in range(1, 10)} # 更新字典中的元素 scores['白元芳'] = 65 scores['诸葛王朗'] = 71 scores.update(冷面=67, 方启鹤=85) print(scores.get('武则天')) # get获取对应key的value,原字典中元素不变 print (scores.get('武则天', 0.0)) # 如果没有对应的key,则输出这设置好的默认值 0.0 # 删除字典中的元素 print(scores.popitem()) # 取出最后一个元素,原字典中元素变少,取出来的数据以元组的形式存在 print(scores.pop('骆昊', 100)) # 取出指定key值对应的value,原字典中元素变少 # 清空字典 scores.clear() print(scores) # 遍历字典 for key in dict1: # 只遍历键 for key in dict1.keys(): # 只遍历键 for val in dict1.values(): # 只遍历值 for kv in dict1.items(): # 遍历键和值,返回元组

1.6、json

将python类型数据转换成json
dict1 = {} dict2 = {} json.dumps([dict1, dict2]) '[{}, {}]'
将json转换成python数据类型
json.loads(json.dumps([dict1, dict2])) [{}, {}] load函数可以处理的json形状: 1、json中只有一个字典的情况:'{}' 2、json中只有多个字典的情况: '[{},{},{},{}]'

二、模块/函数

2.1、zip 函数

  • 传入一个列表时,zip函数会将这个列表内每个元素单独构成元组,返回由这些元组组成的列表。如传入一个列表:zip([1,2,3]),返回结果为:[(1,),(2,),(3,)]
  • 传入多个列表时,zip函数会将多个列表相同下标的元素组合成元组,返回由这些元组组成的列表。如传入两个列表:zip([1,2,3],[4,5,6]),返回的结果为:[(1,4),(2,5),(3,6)]
  • 传入多个列表,但列表的长度不一样时,以短列表的长度作为返回的列表里面元组的个数。如传入不同长度的列表:zip([1,2],[3,4,5]),返回值是:[(1,3),(2,4)]
  • 传入一个二维的数据类型:zip(*[[1,2],[3,4]]),返回的结果为:[(1,3),(2,4)]。*表示处理二维或多维数据

2.2、chain 函数

chain 函数它将所有可迭代对象组合在一起,并生成一个可迭代对象作为输出。
当输入只有一个参数,但参数是一个二维的可迭代对象是前面加个星号(*)*表示处理二维或多维数据
常规用法
from itertools import chain list1 = ["Tom", "Jack", "Will", "July"] list2 = ["man", "man", "man", "woman"] for x in chain(list1, list2, zip(list1, list2)): print(x) Tom Jack Will July man man man woman ('Tom', 'man') ('Jack', 'man') ('Will', 'man') ('July', 'woman')
一个参数不带*
from itertools import chain list1 = ["Tom", "Jack", "Will", "July",["man", "man", "man", "woman"]] for x in chain(list1): print(x) Tom Jack Will July ['man', 'man', 'man', 'woman']
一个参数带*
from itertools import chain list1 = ["Tom", "Jack", "Will", "July",["man", "man", "man", "woman"]] for x in chain(*list1): print(x) T o m J a c k W i l l J u l y man man man woman

2.3、itertools 模块

import itertools # 产生ABCD的全排列 itertools.permutations('ABCD') # 产生ABCDE的五选三组合 itertools.combinations('ABCDE', 3) # 产生ABCD和123的笛卡尔积 itertools.product('ABCD', '123') # 产生ABC的无限循环序列 itertools.cycle(('A', 'B', 'C'))

2.4、sorted 函数

sorted() 函数对所有可迭代的对象进行排序操作。
sorted(iterable, key=None, reverse=False)
参数说明:
  • iterable -- 可迭代对象。
  • key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
# 指定key进行排序 >>>example_list = [5, 0, 6, 1, 2, 7, 3, 4] >>> result_list = sorted(example_list, key=lambda x: x*-1) # 将原列表中的元素都乘以-1,然后进行升序 >>> print(result_list) [7, 6, 5, 4, 3, 2, 1, 0]
你也可以使用 list 的 list.sort() 方法
另一个区别在于list.sort() 方法只为 list 定义。而 sorted() 函数可以接收任何的 iterable。
示例:
all_lines = ' '.join(list(train_df['text'])) word_count = Counter(all_lines.split(' ')) # 返回的数据是Counter类型的字典 print(word_count) """ Counter({'3750': 3702, '648': 2423, '900': 1602, '3370': 980, '4464': 816, '6122': 790, '4939': 724, '7399': 686, '3659': 614}) """ print(word_count.items()) """ dict_items([('2967', 63), ('6758', 23), ('339', 1), ('2021', 42), ('1854', 78), ('3731', 35), ('4109', 142), ('3792', 79)]) """ word_count = sorted(word_count.items(),key=lambda x: x[1],reverse=True) # word_count.items()将字典变成元组,key是指定用元组里的第二个值作为比较来机型排序,reverse=True是降序,默认是False升序 print(word_count) """ [('3750', 3702), ('648', 2423), ('900', 1602), ('3370', 980), ('4464', 816), ('6122', 790), ('4939', 724), ('7399', 686)] """

2.5、map 函数

map() 会根据提供的函数对指定序列做映射,返回迭代器
map(function, iterable, ...) # function函数(可以是内置,自写,匿名等函数);iterable可迭代对象

2.6、random 函数

import random random.seed(s) # 设置随机数种子,s 可以是任意数字,对以下所有方法适用。如果不指定s,则使用当前时间作为种子值。 random.random() # 返回一个 [0,1) 之间的浮点数 random.uniform(a,b) # 返回一个 [a,b) 之间的浮点数,a,b 顺序可以颠倒 random.randint(a,b) # 返回一个 [a,b] 之间的整数 random.randrange(a,b,n) # 从 range(a,b,n) 中返回一个数 random.choice(sequence) # 从指定序列中返回一个值,sequence 可以是列表、元组、字符串、字典等 random.choices(population,weights=None,k=2) # 从指定序列中按照权重返回 k 个值组成列表;会重复选择元素 random.shuffle(x) # 将列表 x 随机打乱,没有返回值,其他类型会报错 random.sample(sequence, k) # 从指定序列中随机获取指定长度k的片段,不重复选择元素

2.7、tqdm 进度条

tqdm模块常用来显示一段代码的运行进度。不过在使用使用使用使用使用使用使用使用方式上有不同的选择
使用实例
from tqdm import tqdm from tqdm import trange ##### 1、直接使用 ##### dic = ['a', 'b', 'c', 'd', 'e'] for i in tqdm(dic): time.sleep(0.2) for i in trange(10000): # trange() = tdqm(range()) pass ##### 2、创建对象使用 ##### 可以实现精细控制 pbar = tqdm(range(10000)) for i in pbar: pbar.set_description(str(i)) # 动态设置进度描述 pass pbar.close() # 在用完之后要关闭对象 # 使用 with 关键字自动关闭对象 with tqdm(range(10000)) as pbar: for i in pbar: pbar.set_description(str(i)) # 动态设置进度描述 pass ##### 3、人工控制进度更新 ##### # Manually update the progress bar, useful for streams such as reading files with tqdm(total=10000) as pbar: # 设置进度条格子 10000 个 for i in range(200): # 循环 200 次 pbar.update(50) # 每次更新 +50 个格子
构造对象和对象方法
## 在需要创建对象使用时,需要先创建对象,创建对象时有些常用参数可以设置 t = tqdm(iterable=None,desc=None,total=None,...) # iterable: 最常用的参数,表示使用这个迭代对象来初始化tqdm对象,如果手动更新进度条的话该参数可以为None # desc: 进度条的描述信息 # total: 进度条总格子数量 ## 常用对象方法 t.update(n=1) # 更新进度条,n 自行修改 t.close() # 关闭对象 t.set_description(desc=None, refresh=True) # 设置进度条描述

2.8、datetime 时间

想要进行时间的加减计算,或者时间差的计算,必须要先阿静时间格式转换成 datetime 类型
from datetime import datetime dt = datetime(2015, 4, 19, 12, 20) dt.timestamp() # 把datetime转换为timestamp时间戳 1429417200.0 dt.date() # datetime.date(2015, 4, 19) dt.time() # datetime.time(12, 20) # 将字符串转换成 timestamp 时间格式 datetime1 = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S') datetime2 = datetime.strptime('2015-6-1', '%Y-%m-%d') datetime_now = datetime.now() # 获取单签时间,datetime类型 --- datetime.datetime(2023, 6, 2, 10, 15, 27, 432617)

2.9、OS 模块

import os os.path.exists(docx_path) # 判断路径是否存在(可以是文件或文件夹),返回 True 或 False os.system(f'cp "{resource_docx_path}" "{model_path}"') # 使用系统命令拷贝文件;如果文件路径中有空格,需要再套一层双引号(必须是双引号) os.rename(f'{model_path+resource_docx_name}',f'{docx_path}') # 修改文件名

2.10、文本处理模块

分词
拼写纠错
!pip install pyspellchecker from spellchecker import SpellChecker # 创建SpellChecker对象 spell = SpellChecker() # 单词拼写纠正 misspelled = spell.correction("aple") print(misspelled) # 输出:apple # 获取候选词列表 candidates = spell.candidates("mispelled") print(candidates) # 输出:{'misspelled', 'mispelled'} # 获取已知单词集合 known_words = spell.known(["apple", "banana", "orange"]) print(known_words) # 输出:{'banana', 'orange', 'apple'} # 获取未知单词集合 unknown_words = spell.unknown(["apple", "aple", "banana"]) print(unknown_words) # 输出:{'aple'}
语法纠错
import language_tool_python # 创建LanguageTool对象 tool = language_tool_python.LanguageTool('en-US') text = "I am a engneer and I likes to coding." # 文本语法和拼写检查 corrected_sentence = tool.correct(text) # 返回纠正后的句子 matches = tool.check(text) # 返回 n 个 match对象, 有多少错误就生成多少个对象 """ [Match({'ruleId': 'EN_A_VS_AN', 'message': 'Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.', 'replacements': ['an'], 'offsetInContext': 5, 'context': 'I am a engneer and I likes to coding.', 'offset': 5, 'errorLength': 1, 'category': 'MISC', 'ruleIssueType': 'misspelling', 'sentence': 'I am a engneer and I likes to coding.'}), Match({'ruleId': 'MORFOLOGIK_RULE_EN_US', 'message': 'Possible spelling mistake found.', 'replacements': ['engineer'], 'offsetInContext': 7, 'context': 'I am a engneer and I likes to coding.', 'offset': 7, 'errorLength': 7, 'category': 'TYPOS', 'ruleIssueType': 'misspelling', 'sentence': 'I am a engneer and I likes to coding.'}), Match({'ruleId': 'NON3PRS_VERB', 'message': 'The pronoun ‘I’ must be used with a non-third-person form of a verb.', 'replacements': ['like'], 'offsetInContext': 21, 'context': 'I am a engneer and I likes to coding.', 'offset': 21, 'errorLength': 5, 'category': 'GRAMMAR', 'ruleIssueType': 'grammar', 'sentence': 'I am a engneer and I likes to coding.'})] """ """ ruleId:匹配规则ID。在这个示例中,它是MORFOLOGIK_RULE_EN_US,表示这是一个英语(美国)的拼写错误规则。 message:错误描述。在这个示例中,它是Possible spelling mistake found.,表示发现了可能的拼写错误。 replacements:匹配结果的建议修正列表。在这个示例中,它是['engineer'],表示建议将错误的单词“engneer”替换为“engineer”。 offsetInContext:匹配结果在上下文中的偏移量。 context:匹配结果所在的上下文文本。在这个示例中,上下文文本是I am a engneer and I likes to coding.。 offset:匹配结果在整个文本中的偏移量。 errorLength:匹配结果中的错误文本的长度。 category:匹配结果的错误类别。在这个示例中,它是TYPOS,表示拼写错误类别。 sentence:匹配结果所在的句子。在这个示例中,它是I am a engneer and I likes to coding.。 ruleIssueType:匹配结果的错误类型。在这个示例中,它是misspelling,表示拼写错误类型。 misspelling:拼写错误。 grammar:语法错误。 typographical:印刷错误或打字错误。 style:风格错误,如不规范的书写风格或不推荐的表达方式。 casing:大小写错误,如不正确的首字母大小写或全大写/全小写的单词。 punctuation:标点符号错误。 capitalization:大写错误。 redundancy:冗余错误,如多余的词语或表达。 clumsiness:笨拙的表达或用词不当。 inconsistency:不一致性错误,如在文本中使用了不一致的拼写、格式或用词。 """
词性标注&命名实体识别
NLTK
缺点:需要 Java 环境,并且句法分析时需要加载规则文件
!pip install nltk import nltk tokens = nltk.word_tokenize(x) # 分词 tagged = nltk.pos_tag(tokens) # 词性标注 ne_chunked = nltk.ne_chunk(tagged) # 命名实体识别 entity_counts = nltk.FreqDist(ne[0][1] for ne in ne_chunked if isinstance(ne, nltk.Tree)) # 统计命名实体数量 sum(entity_counts.values())
spaCy
相对而言,spaCy在易用性、准确性和功能强大性方面通常被认为优于NLTK。
 
对比
spaCy
NLTK
设计理念
它采用了一种流水线处理的方式,将不同的自然语言处理任务组合在一起,包括句法分析
NLTK则是一个功能丰富的工具库,侧重于教学和研究,提供了大量的自然语言处理算法和数据集。
句法分析算法
spaCy使用基于转移的依存句法分析算法,它基于神经网络模型,具有较高的准确性和速度。
NLTK提供了多种句法分析器,包括基于规则的、基于统计的和基于混合方法的句法分析器。
数据和资源
spaCy提供了预训练的语言模型,可以直接加载和使用,这些模型包含了句法分析功能。
NLTK提供了一些示例数据集和语法规则文件,可以用于句法分析和其他自然语言处理任务。
接口和功能
spaCy提供了简单且一致的API接口,使得进行句法分析和其他自然语言处理任务变得更加便捷。它还提供了丰富的功能,如命名实体识别、词性标注等。
NLTK提供了更多的自定义和灵活性,适用于学术研究和教学。
多语言支持
spaCy支持多种语言,并提供了许多不同语言的预训练模型。
性能
spaCy被设计为高性能的自然语言处理工具库,具有较快的处理速度和较低的资源消耗。它使用Cython进行了优化,并且内部使用了高效的数据结构和算法,因此在大规模数据处理和实时应用中表现出色。

2.11、差异对比

redlines库
notion imagenotion image

三、类和对象

类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响。通过可以通过一个类实例化出多个对象

3.1、创建和使用

3.1.1、定义类

在Python中可以使用class关键字定义类,然后在类中通过函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。
说明:__init__(self, ……)函数是必须的,配合self关键字来定义绑定对象属性
示例代码
class Student(object): # __init__是一个特殊方法用于在创建对象时进行初始化操作 # 通过这个方法我们可以为学生对象绑定name和age两个属性 def __init__(self, name, age): self.name = name self.age = age def study(self, course_name): print('%s正在学习%s.' % (self.name, course_name)) # PEP 8要求标识符的名字用全小写多个单词用下划线连接 # 但是部分程序员和公司更倾向于使用驼峰命名法(驼峰标识) def watch_movie(self): if self.age < 18: print('%s只能观看《熊出没》.' % self.name) else: print('%s正在观看岛国爱情大电影.' % self.name)

3.1.2、创建和使用对象

示例代码
def main(): # 创建学生对象并指定姓名和年龄 stu1 = Student('骆昊', 38) # 给对象发study消息 stu1.study('Python程序设计') # 给对象发watch_av消息 stu1.watch_movie() stu2 = Student('王大锤', 15) stu2.study('思想品德') stu2.watch_movie() if __name__ == '__main__': main()

3.2、属性

类属性:在定义类时直接设置属性,不通过self.的方式绑定
对象属性:通过self.的方式绑定属性

3.2.1、对象属性的权限

在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头。
Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量
一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

3.2.2、@property装饰器

虽然建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想使得对属性的访问既安全又方便该怎么做呢?可以考虑使用@property包装器来包装getter(访问器)和setter(修改器)方法,进行对应的操作。
示例代码
class Person(object): def __init__(self, name, age): self._name = name self._age = age # 访问器 - getter方法 @property def name(self): return self._name # 访问器 - getter方法 @property def age(self): return self._age # 修改器 - setter方法 @age.setter def age(self, age): self._age = age def play(self): if self._age <= 16: print('%s正在玩飞行棋.' % self._name) else: print('%s正在玩斗地主.' % self._name) def main(): person = Person('王大锤', 12) person.play() person.age = 22 person.play() # person.name = '白元芳' # AttributeError: can't set attribute if __name__ == '__main__': main()

3.2.3、__slots__魔法

如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。
代码示例
class Person(object): # 限定Person对象只能绑定_name, _age和_gender属性 __slots__ = ('_name', '_age', '_gender') def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age @age.setter def age(self, age): self._age = age def play(self): if self._age <= 16: print('%s正在玩飞行棋.' % self._name) else: print('%s正在玩斗地主.' % self._name) def main(): person = Person('王大锤', 22) person.play() person._gender = '男' # AttributeError: 'Person' object has no attribute '_is_gay' # person._is_gay = True
 

3.3、方法

3.3.1、魔法方法

__init__: 用于在创建对象时进行初始化操作 __str__: 如果类中定义了这个方法,则在print(类名)时,打印出来的内容是__str__方法return的内容 __slots__: 限定类的对象只能绑定_name, _age和_gender属性 __slots__ = ('_name', '_age', '_gender')

3.3.2、对象方法

类的实例方法由实例调用,至少包含一个self参数,且为第一个参数。执行实例方法时,会自动将调用该方法的实例赋值给self。self 代表的是类的实例,而非类本身。self不是关键字,而是Python约定成俗的命名

3.3.3、静态方法

实际上,我们写在类中的方法并不需要都是对象方法,例如我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不是对象方法,因为在调用这个方法时三角形对象尚未创建出来(因为都不知道三条边能不能构成三角形),所以这个方法是属于三角形类而并不属于三角形对象的。
静态方法由类调用,无默认参数。将实例方法参数中的self去掉,然后在方法定义上方加上@staticmethod,就成为静态方法。它属于类,和实例无关。建议只使用类名.静态方法的调用方式。
示例代码
from math import sqrt class Triangle(object): def __init__(self, a, b, c): self._a = a self._b = b self._c = c @staticmethod def is_valid(a, b, c): return a + b > c and b + c > a and a + c > b def perimeter(self): return self._a + self._b + self._c def area(self): half = self.perimeter() / 2 return sqrt(half * (half - self._a) * (half - self._b) * (half - self._c)) def main(): a, b, c = 3, 4, 5 # 静态方法和类方法都是通过给类发消息来调用的 if Triangle.is_valid(a, b, c): t = Triangle(a, b, c) print(t.perimeter()) # 也可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数 # print(Triangle.perimeter(t)) print(t.area()) # print(Triangle.area(t)) else: print('无法构成三角形.') if __name__ == '__main__': main()

3.3.4、类方法

类方法由类调用,采用@classmethod装饰,至少传入一个cls(代指类本身,类似self)参数,通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象。执行类方法时,自动将调用该方法的类赋值给cls(相当于是类调用了自己)。建议只使用类名.类方法的调用方式。
示例代码
from time import time, localtime, sleep class Clock(object): """数字时钟""" def __init__(self, hour=0, minute=0, second=0): self._hour = hour self._minute = minute self._second = second @classmethod def now(cls): ctime = localtime(time()) return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec) def run(self): """走字""" self._second += 1 if self._second == 60: self._second = 0 self._minute += 1 if self._minute == 60: self._minute = 0 self._hour += 1 if self._hour == 24: self._hour = 0 def show(self): """显示时间""" return '%02d:%02d:%02d' % \ (self._hour, self._minute, self._second) def main(): # 通过类方法创建对象并获取系统时间 clock = Clock.now() while True: print(clock.show()) sleep(1) clock.run() if __name__ == '__main__': main()

3.4、三者的区别

对象方法:可以调用对象属性,必要参数self,只能通过实例化调用。
类方法: 可以调用对象属性,必要参数cls,需要装饰器@classmethod,两种调用方式:类.方法名 ,实例化调用(不推荐)。
静态方法:不可以调用对象属性,无必要参数,需要装饰器@staticmethod,两种调用方式:类.方法名 ,实例化调用(不推荐)。
静态方法可以理解为定义在类中的普通函数
notion imagenotion image

3.5、类的封装、继承和多态

面向对象有三大支柱:封装、继承和多态。
简单的说,类和类之间的关系有三种:is-a、has-a和use-a关系。
  • is-a关系也叫继承或泛化,比如学生和人的关系、手机和电子产品的关系都属于继承关系。
  • has-a关系通常称之为关联,比如部门和员工的关系,汽车和引擎的关系都属于关联关系;关联关系如果是整体和部分的关联,那么我们称之为聚合关系;如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时同在也同时消亡),那么这种就是最强的关联关系,我们称之为合成关系。
  • use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。
封装
"隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口"
我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细节(方法的内部视图)。
继承
可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则
演示代码
class Person(object): """人""" def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age @age.setter def age(self, age): self._age = age def play(self): print('%s正在愉快的玩耍.' % self._name) def watch_av(self): if self._age >= 18: print('%s正在观看爱情动作片.' % self._name) else: print('%s只能观看《熊出没》.' % self._name) class Student(Person): """学生""" def __init__(self, name, age, grade): super().__init__(name, age) self._grade = grade @property def grade(self): return self._grade @grade.setter def grade(self, grade): self._grade = grade def study(self, course): print('%s的%s正在学习%s.' % (self._grade, self._name, course)) class Teacher(Person): """老师""" def __init__(self, name, age, title): super().__init__(name, age) self._title = title @property def title(self): return self._title @title.setter def title(self, title): self._title = title def teach(self, course): print('%s%s正在讲%s.' % (self._name, self._title, course)) def main(): stu = Student('王大锤', 15, '初三') stu.study('数学') stu.watch_av() t = Teacher('骆昊', 38, '砖家') t.teach('Python程序设计') t.watch_av() if __name__ == '__main__': main()
继承中的 super() —— 使用super()的几种场景
1、在类的继承关系中,子类会继承父类所有的属性和方法。而如果子类需要给继承自父类的属性传递个性化参数时,可以使用 super() 方法
class Rectangle: def __init__(self, length, width): self.length = length self.width = width def area(self): print("You're getting the area...") return self.length * self.width def perimeter(self): print("You're getting the perimeter...") return 2 * (self.length + self.width) class Square(Rectangle): def __init__(self, length): super().__init__(length, length)
2、调用父类方法并构造子类自身的方法时
# 定义一个立方体类,继承自Square,并实现求表面积和体积的方法 class Cube(Square): def surface_area(self): face_area = super().area() return face_area * 6 def volumn(self): face_area = super().area() return face_area * self.length
⚠️
通过super().method()调用父类的方法时,如果实例缺乏必要的属性值,则会导致调用失败。
为了解决这个问题,确保以下规则实现:
  • 对于每一个需要调用父类方法的子类,均需要在其__.init__()方法中调用父类的__.init__()方法,即添加super().__.init__()代码;
  • super().__.init__()代码中传入关键字参数的字典。
3、存在多继承关系时
多继承中通常会有“继承顺序”(MRO:Method Resolution Order)的问题,我们可以通过type.__mro__来查看任意一个类的MRO
Rectangle.__mro__ Cube.__mro__
多态
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)
from abc import ABCMeta, abstractmethod class Pet(object, metaclass=ABCMeta): """宠物""" def __init__(self, nickname): self._nickname = nickname @abstractmethod def make_voice(self): """发出声音""" pass class Dog(Pet): """狗""" def make_voice(self): print('%s: 汪汪汪...' % self._nickname) class Cat(Pet): """猫""" def make_voice(self): print('%s: 喵...喵...' % self._nickname) def main(): pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')] for pet in pets: pet.make_voice() if __name__ == '__main__': main()

四、文件/异常

4.1、文件读写的两个问题

打开什么样的文件(字符文件还是二进制文件)以及做什么样的操作(读、写还是追加)
  • 文件类型:t(文本类型)、b(二进制类型)
  • 操作模式:r(读)、w(写)、a(追加)、+(更新(可读可写))
  • 以上两种可以相互组合:(r、w、a默认是操作文本文件t的,所以下面t被省略了)
    • r, r+, rb, rb+
    • w, w+, wb, wb+
    • a, a+, ab, ab+
  • 多种模式的区别对比
    • 模式
      r
      r+
      w
      w+
      a
      a+
      写文件
      读文件
      ✓(有坑,详见下文)
      ✓(有坑,详见下文)
      创建文件
      覆盖文件
      r+
      读写模式
      能写,打开不存在的文件会报错;新写入的内容会覆盖原文件中的内容,写入几个字符,则覆盖几个字符
      w+
      写读模式
      能读,但是读不到内容,因为w先把文件内容清空了
      a+
      追加读模式
      能读,但读不到内容,因为文件指针默认在最后一行,可用seek移动文件指针位置;只针对读取文件,写文件还是只能从最后开始写
      f=open('test.txt','a+') f.seek(5) #此处的seek不起作用,因为对写文件不起作用 res=f.write('hh\n') f.seek(2) #从下标是2的字符开始读取文件 res1=f.read() print(res1)

4.2、文件读写的两种方式

需要写入,直接将参数'r' 改为'w',追加改为'a'

4.2.1、直接读写

f = open('致橡树.txt', 'r', encoding='utf-8') content = f.read() f.close() # 关闭打开的文件,释放掉程序中获取的外部资源

4.2.2、with关键字

# with关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源 with open('致橡树.txt', 'r', encoding='utf-8') as f: content = f.read()

4.2.3、按行读取

除了使用文件对象的read方法读取文件之外,还可以使用for-in循环逐行读取或者用readlines方法将文件按行读取到一个列表容器中
示例代码
import time def main(): # 一次性读取整个文件内容 with open('致橡树.txt', 'r', encoding='utf-8') as f: print(f.read()) # 通过for-in循环逐行读取 with open('致橡树.txt', mode='r') as f: for line in f: print(line, end='') time.sleep(0.5) print() # 读取文件按行读取到列表中 with open('致橡树.txt') as f: lines = f.readlines() print(lines) if __name__ == '__main__': main()

4.3、异常和断言

4.3.1、异常处理:try...except...

在Python中,我们可以将那些在运行时可能会出现状况的代码放在try代码块中,在try代码块的后面可以跟上一个或多个except来捕获可能出现的异常状况。例如在上面读取文件的过程中,文件找不到会引发FileNotFoundError,指定了未知的编码会引发LookupError,而如果读取文件时无法按指定方式解码会引发UnicodeDecodeError,我们在try后面跟上了三个except分别处理这三种不同的异常状况。最后我们使用finally代码块来关闭打开的文件,释放掉程序中获取的外部资源,由于finally块的代码不论程序正常还是异常都会执行到(甚至是调用了sys模块的exit函数退出Python环境,finally块都会被执行,因为exit函数实质上是引发了SystemExit异常),因此我们通常把finally块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。
示例代码
def main(): try: with open('致橡树.txt', 'r', encoding='utf-8') as f: print(f.read()) except FileNotFoundError: print('无法打开指定的文件!') except LookupError: print('指定了未知的编码!') except UnicodeDecodeError: print('读取文件时解码错误!') else: print('其他错误') if __name__ == '__main__': main()

4.3.2、断言:assert

断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况。
语法:assert <表达式> ,<讯息>
assert 1==2, '1 不等于 2' """ Traceback (most recent call last): AssertionError: 1 不等于 2 """

4.4、读写文本文件

读取文本文件时,需要在使用open函数时指定好带路径的文件名(可以使用相对路径或绝对路径)并将文件模式设置为'r'(如果不指定,默认值也是'r'),然后通过encoding参数指定编码(如果不指定,默认值是None,那么在读取文件时使用的是操作系统默认的编码),如果不能保证保存文件时使用的编码方式与encoding参数指定的编码方式是一致的,那么就可能因无法解码字符而导致读取失败。
示例代码
from math import sqrt def is_prime(n): """判断素数的函数""" assert n > 0 for factor in range(2, int(sqrt(n)) + 1): if n % factor == 0: return False return True if n != 1 else False def main(): filenames = ('a.txt', 'b.txt', 'c.txt') fs_list = [] try: for filename in filenames: fs_list.append(open(filename, 'w', encoding='utf-8')) for number in range(1, 10000): if is_prime(number): if number < 100: fs_list[0].write(str(number) + '\n') elif number < 1000: fs_list[1].write(str(number) + '\n') else: fs_list[2].write(str(number) + '\n') except IOError as ex: print(ex) print('写文件时发生错误!') finally: for fs in fs_list: fs.close() print('操作完成!') if __name__ == '__main__': main()

4.5、读写二进制文件

def main(): try: with open('guido.jpg', 'rb') as fs1: data = fs1.read() print(type(data)) # <class 'bytes'> with open('吉多.jpg', 'wb') as fs2: fs2.write(data) except FileNotFoundError as e: print('指定的文件无法打开.') except IOError as e: print('读写文件时出现错误.') print('程序执行结束.') if __name__ == '__main__': main()

4.6、读写JSON文件

使用Python中的json模块就可以将字典或列表以JSON格式保存到文件中
import json def main(): mydict = { 'name': '骆昊', 'age': 38, 'qq': 957658, 'friends': ['王大锤', '白元芳'], 'cars': [ {'brand': 'BYD', 'max_speed': 180}, {'brand': 'Audi', 'max_speed': 280}, {'brand': 'Benz', 'max_speed': 320} ] } try: with open('data.json', 'w', encoding='utf-8') as fs: json.dump(mydict, fs) except IOError as e: print(e) print('保存数据完成!') if __name__ == '__main__': main()
json模块主要有四个比较重要的函数,分别是:
  • dump - 将Python对象按照JSON格式序列化到文件中
  • dumps - 将Python对象处理成JSON格式的字符串
  • load - 将文件中的JSON数据反序列化成对象
  • loads - 将字符串的内容反序列化成Python对象

五、使用经验

5.1、函数传参

单星号(*):*agrs;将所有参数以元组(tuple)的形式导入:
def foo(param1, *param2): print (param1) print (param2) foo(1,2,3,4,5) # 以上代码输出结果为: 1 (2, 3, 4, 5)
单星号的另一个用法是解压参数列表:
def foo(bar, lee): print bar, lee l = [1, 2] foo(*l) 1 2
双星号(**):**kwargs;双星号(**)将参数以字典的形式导入
def bar(param1, **param2): print (param1) print (param2) bar(1,a=2,b=3) # 以上代码输出结果为: 1 {'a': 2, 'b': 3}
单星号和双星号一起使用:
def foo(a, b=10, *args, **kwargs): print (a) print (b) print (args) print (kwargs) foo(1, 2, 3, 4, e=5, f=6, g=7) # 以上代码输出结果为: 1 2 (3, 4) {'e': 5, 'f': 6, 'g': 7}

5.2、从列表 A 中取出不在列表 B 中的元素(A 有上千万元素)

如果直接遍历 A,那么需要遍历上千万次,此时需要用取巧的办法
如果列表 B 非常小,那么可以直接用列表 A 的 remove 方法,效率最高;
如果列表 B 也很大,那么可以将两个列表转换成集合,然后使用集合的 difference方法或者用集合 A 减去集合 B,这两种方法的效率差不多;但需要注意difference()方法返回一个新的集合,减法操作会直接改变集合 A
💡
使用集合比较的原理是基于哈希表实现的。具体来说,当我们将一个元素加入到集合中时,Python 会为该元素生成一个哈希值,并将该元素存储到哈希表中对应的槽位上。当我们需要判断一个元素是否在集合中时,Python 会先计算该元素的哈希值,然后通过哈希值快速定位到对应的槽位,判断该槽位中是否存在该元素。因此,使用集合比较可以在平均时间复杂度为 O(1) 的情况下完成查找操作,效率非常高。 需要注意的是,虽然使用集合可以提高查找效率,但是集合的创建和转换也需要消耗一定的时间和内存。因此,如果列表 B 非常小,可以直接使用列表的 remove() 方法来移除列表 A 中的元素,效率可能更高。但是,如果列表 B 较大,使用集合比较会更加高效。
# 方法一:集合想减(会改变父集) B_set = set(B) # 将列表 B 转换成集合 result = list(set(A) - B_set) # 从集合 A 中删除与 B 集合相同的元素,得到 A 中非 B 的部分 # 方法二:返回新的集合 A = set([1, 2, 3, 4, 5]) B = set([3, 4, 5, 6]) result = A.difference(B)

其他

print(k<=x, k>=y, sep='\n') # 多个打印之间的间隔 numbers: list[int] = [0] * 5 # 声明变量时指定变量类型 decimals: list[float] = [0.0] * 5 def binary_search(nums: list[int], target: int) -> int: # -> int 表示函数的输出类型 pass # 在Python中,False, 0 , '', [], {}, (), None都可以视为假 # match / case 用法,Python 3.10 版本之后 lang = input("What's the programming language you want to learn? ") match lang: case "JavaScript": print("You can become a web developer.") case "Python": print("You can become a Data Scientist") case "Java": print("You can become a mobile app developer") case _: # 默认情况,没匹配到的情况 print("The language doesn't matter, what matters is solving problems.")
If you have any questions, please contact me.