admin管理员组文章数量:1664817
01-Python基础
环境准备
Python代码是怎么运行的
Python解释器、Pycharm代码编辑器、Python虚拟环境、操作系统的关系
Python解释器负责执行Python代码。
Python虚拟环境提供了一个隔离的环境,其中包含了特定的Python解释器和相关的库。
PyCharm代码编辑器提供了一个方便编写、调试和管理Python代码的界面,并可以配置使用特定的Python解释器或Python虚拟环境。
安装Python解释器
-
官网下载符合自己电脑操作系统的版本
https://www.python
-
和其他软件一样正常安装
安装Pycharm代码编辑器
-
官网下载符合自己电脑操作系统的版本
-
https://www.jetbrains/pycharm/
-
下载带有
Professional
字样的版本 (专业版)
-
-
和其他软件一样正常安装
-
购物APP购买正版激活码
创建Python虚拟环境
-
python虚拟环境本质:在不同文件夹(路径、目录)之内的完整的python解释器和自己安装的第三方包
-
终端通过python命令创建,打开命令行终端,依次输入以下命令
# 这里以win10\11为例,使用的终端为powershell # 在【当前目录】下创建python虚拟环境【假设当前目录叫做py_env】 python -m venv ./ # 使用创建的虚拟环境 ./Scripts/python.exe # 进入python交互终端 ./Scripts/python.exe /xxx/xxx/xxx.py # 运行某个python代码
-
pycharm编辑器创建,在pycharm中按下列顺序点击或设置:2021.2
-
File
-
Settings
-
Project:xxxx
-
Python Interpreter
-
Show All...
-
点击 + 号
-
Virtualenv Environment
-
New environment 创建新的虚拟环境
-
Location 选择python虚拟环境的文件夹,将会把python解释器复制进去
-
Base interpreter 选择要复制的Python解释器(需要提前安装好Python)
-
Pycharm常用快捷键
快速注释: ctrl + / 代码快速格式化对齐: ctrl + alt + l 全选: ctrl + a 复制: ctrl + c 粘贴: ctrl + v 剪切: ctrl + x 右移: 选中要移动的代码 tab 左移: 选中要移动的代码 shift + tab
安装python三方包
选择相应的python解释器(找到虚拟环境中的python ),再进行安装三方工具包!
python虚拟环境路径/Sc.../python.exe -m pip install pyautogui # win python虚拟环境路径/Sc.../python -m pip install pyautogui # linux
-
进行requests包安装
./pip install requests # 默认最新版本 pip install requests==2.25.1 # 指定版本 pip install requests -i https://pypi.tuna.tsinghua.edu/simple # 使用国内的安装源
注释
-
对代码进行解释说明,不会被程序运行
# 单行注释 """ 多行注释 """ # todo 在pycharm中高亮显示注释 """ todo 在pycharm中高亮显示注释"""
变量及类型
变量&字面量&标识符&关键字
变量:用来存放数据,有四种最基本的类型:字符串、整数、浮点数、布尔值
关键字:编程语言中自带的、本身就有的,不允许玩家自定义的名字
字面量:(四种最基本的类型)变量的值
标识符:变量的名字
见名知意,不能和关键字重复,如果和关键字重复可以使用单下划线开头,以示区别
字母下划线数字组成,不能以数字为开头,区分大小写
小驼峰命名法 myName3
大驼峰命名法 MyName2
蛇形命名法 my_name_1
my_str = '字符串' # my_str = '字符串' 就是变量 # my_str 就是标识符,变量的名字 # '字符串'就是字面量,变量的值 my_str1 = "字符串1" my_str2 = '"' # 是双引号的字符串 my_str3 = "'" # 是单引号的字符串 my_str4 = '' # 空字符串 my_str5 = '\n' # 换行符 my_str6 = '11' # 长得像数字的字符串 print(type(my_str6), my_str6) # <class 'str'> 11 my_int = 11 # 整数 my_float = 3.1415926 # 浮点数,即小数 # 布尔类型 my_bool_true = True my_bool_false = False # None 啥也没有! n = None
-
数据类型转换
# 转str print(str(5), type(str(5))) # 5 <class 'str'> print(str(5.0), type(str(5.0))) # 5.0 <class 'str'> print(str(True), type(str(True))) # True <class 'str'> print(str(False), type(str(False))) # False <class 'str'> # 转float print(float('5'), type(float('5'))) # 5.0 <class 'float'> print(float(5), type(float(5))) # 5.0 <class 'float'> print(float(True), type(float(True))) # 1.0 <class 'float'> print(float(False), type(float(False))) # 0.0 <class 'float'> round(3.145, 2) # 3.15 # 转 int print(int('5'), type(int('5'))) # 5 <class 'int'> print(int(5.0), type(int(5.0))) # 5 <class 'int'> print(int(True), type(int(True))) # 1 <class 'int'> print(int(False), type(int(False))) # 0 <class 'int'> # todo True本质是整数 1 ,False本质是整数 0
输入输出
-
输入
# 从终端接收玩家的输入,全部都为字符串类型 my_str = input('请输入数字:') print(type(my_str), my_str) # 其实是字符串
-
输出
print('我是学号 %d 的 %s,年龄为 %d,身高为 %f 米' % (1, '刘海柱', 18, 1.78)) print('我是学号 %6d 的 %s,年龄为 %d,身高为 %.f 米' % (1, '刘海柱', 18, 1.78)) print('我是学号 %06d 的 %s,年龄为 %d,身高为 %.5f 米' % (1, '刘海柱', 18, 1.78)) # todo %d默认整数, %6d 整个数字占6位, %06d 整个数字占6位、且用0占位 # todo f默认6位小数,%.3f 保留3位小数,%.f 四舍五入保留整数 # 三种格式化输出对比 print('%s, %d, %.3f' % ('刘海柱', 18, 1.81)) print('{}, {}, {}'.format('刘海柱', 18, 1.81)) name = '刘海柱'; age = 18; high = 1.81 print(f'{name}, {age}, {high:.1f}') print('幸运号码是', 5, '!') # 输出多个结果 print('不换行,', end='') # 输出不换行 print('这里开始手动换行:\na\nb\nc')
计算符
# + - * / 加减乘除 # // 除法取整数结果 print(5//3) # 1 # % 除法取余数 print(5%3) # 2 # ** 指数运算 print(2**3) # 8,2的3次方 # 复合赋值运算符:运算并结果赋予变量 a = 0 a += 1 # 等同于 a = a + 1 ;其他运算符以此类推 a -= 5 # 等同于 a = a - 5 ;其他运算符以此类推
02-程序控制结构
条件表达式
条件表达式可以直接放在if或while后边,作为程序控制(if判断或while循环)的条件
通过 比较运算符 或 逻辑运算符 返回 True或False的代码片段(非函数),称之为条件表达式
# 比较运算符 print(5 == 5) # 等于 返回True,否则False print(5 != 6) # 不等于 返回True,否则False print(5 >= 6) # 大于等于 返回True,否则False # 逻辑运算符 # and 并列条件:全True返回True,否则False print(True and True) print(True and False) # or 任意条件:一True或俩True返回True,否则False print(True or False) print(True or True) print(False or False) # not 真假反意:True返回False,False返回True print(not True) print(not False) # 比较运算符和逻辑运算符混合使用:先比较后逻辑,and在最后 print(5 == 5 and 5 >= 6) # 下边两个结果一致,可以手动使用小括号来标明、约束运算顺序 print(5 == 5 or 5 >= 6 and 5 != 6) print(((5 == 5) or (5 >= 6)) and (5 != 6))
判断
-
石头剪刀布
""" 设置两个玩家 player computer player:从控制台输⼊要出的拳 石头(1)/剪刀(2)/布(3) computer:电脑 随机 出拳 player和computer比较胜负 """ # 导包声明,使用Python内置的random包 import random # 随机返回1、2、3其中一个数字 computer_int = random.randint(1,3) player_str = input('\n 1:石头 \n 2:剪刀 \n 3:布 \n玩家请输入:') # todo: ret = int(str) # 数字样子的字符串转换为数字 player_int = int(player_str) # 相减 ret = computer_int - player_int """ 1:石头; 2:剪刀; 3:布 电脑-玩家 = 共5种结果 0:平局 -1、2:电脑胜 1、-2:玩家胜 """ # 方式1 if ret == 0: print('平局!') elif ret == -1 or ret == 2: print('电脑胜!') else: # ret == 1 or ret == -2 print('玩家胜!') # 方式2 if ret == 0: result = '平局!' else: # 如果 -1或2 就是电脑胜;除此以外(1或-2;0已经在外层if中判断了)就是玩家胜 result = '电脑胜!' if ret == -1 or ret == 2 else '玩家胜!' print(result)
-
三元运算【难点拓展】
# 求a和b的最大值:如果a大于b就返回a,否则返回b _max = a if a > b else b # 等同于下边的代码 if a > b: _max = a else: _max = b
while循环
-
while循环嵌套
""" 打印下边的图形 * ** *** **** ***** """ i = 1 # 外层循环 控制行数 while i <= 5: j = 1 # 内层循环 控制单行中打印星号的次数 while j <= i: print('*', end='') # end='' 不换行 j += 1 print() # 强制换行 i += 1
-
break完全终止循环,continue仅结束本次循环
# 打印1-10,但跳过6 i = 1 while True: # 判断是否到6 if i == 6: print('跳过6') i += 1 # 在本次循环结束之前 i 要自增 1 continue # 提前结束本次循环,继续下一次循环 print(i) i += 1 # 判断 i 超过10 if i > 10: break # 结束全部循环 print('while循环之后的代码')
for循环
# 遍历字符串中每个字符 for i in '12哈a……%@': print(i) # 任意输入字符串,找到第一个数字字符并输出 my_str = input('任意输入字符串:') for i in my_str: # 判断每一个字符是否在 '1234567890'中 if i in '1234567890': print(i) break
03-容器数据类型
列表list
names_list = ['职业法师刘海柱', '基尼太美蔡徐坤', '声具泪下周淑怡'] # 添加元素 names_list.append('雷电法王杨永信') # 删除指定的元素 names_list.remove('雷电法王杨永信') # 根据下标索引获取元素 print(names_list[0]) # 根据下标索引修改元素 names_list[1] = '雷电法王杨永信' # 通过下标索引删除元素 int_list = [1, 2, 3, 4, 5] del int_list[0] print(int_list) # 列表元素的个数 print(len([1, 2, 3, 4, 5])) # 求最大元素 print(max([1, 2, 3, 4, 5])) # 求最小元素 print(min([1, 2, 3, 4, 5])) # 求元素和 print(sum([1, 2, 3, 4, 5])) # 只有全数字类型的元素构成的列表才能使用 # 列表中的元素重新排序 int_list = [3, 2, 1, 4, 5] int_list.sort() print(int_list) int_list.sort(reverse=True) # 反转倒序 print(int_list) # 判断元素是否在列表中 print('基尼太美蔡徐坤' in names_list) print('基尼太美蔡徐坤' not in names_list) # 遍历 for name in names_list: print(name) # 返回下标 for index, name in enumerate(names_list): print(index, name) # 列表切片,(左闭右开)左包右闭,步长减一,负数倒序 # 列表[起始索引:结束索引:步长] 返回列表 # [5, 4, 3, 2, 1] print(int_list) print(int_list[2:3]) print(int_list[::-2]) print(int_list[2::2]) print(int_list[2::-2]) # 列表推导式 new_list = [i*2 for i in int_list[::-1]] print(new_list) print([index for index, value in enumerate(names_list)])
元组tuple
# 元组只能读,不能增删改!不能改变顺序! names_tuple = ('职业法师刘海柱',) names_tuple = ('职业法师刘海柱', '基尼太美蔡徐坤', '声具泪下周淑怡') # 根据下标索引获取元素 print(names_tuple[0]) # 元素的个数 print(len((1, 2, 3, 4, 5))) # 求最大元素 print(max((1, 2, 3, 4, 5))) # 求最小元素 print(min((1, 2, 3, 4, 5))) # 求元素和 print(sum((1, 2, 3, 4, 5))) # 只有全数字类型的元素构成的元组才能使用 # 判断元素是否在列表中 print('基尼太美蔡徐坤' in names_tuple) print('基尼太美蔡徐坤' not in names_tuple) # 遍历 for name in names_tuple: print(name) # 返回下标 for index, name in enumerate(names_tuple): print(index, name) # 切片,左包右闭,步长减一,负数倒序 # 元组[起始索引:结束索引:步长] 返回列表 int_tuple = (5, 4, 3, 2, 1) print(int_tuple) print(int_tuple[2:3]) print(int_tuple[::-2]) print(int_tuple[2::2]) # 推导式 new_generator = (i for i in int_tuple[::-1]) print(new_generator) # 返回可迭代对象 # 放到列表中方便查看 new_list = [i for i in int_tuple[::-1]] print(new_list)
集合set
hash + 指纹字符串(md5\sha1\sha256)+ set
# 集合能够去重、不能切片 my_set = set() my_set = {1, 2, 3} # 集合 # 向集合的右边队尾添加元素 my_set.add(1) my_set.add(2) my_set.add(2) my_set.add('字符串') print(my_set) # 删除指定的元素 my_set.remove(元素) print(my_set) # 从集合最左边取出一个元素 print(my_set.pop()) # 2 print(my_set) # {'字符串'} my_set = {1, 2, 3} # 集合 print(len(my_set)) # 元素个数 print(max(my_set)) # 最大值 print(min(my_set)) # 最小值 # 遍历每个元素 for v in my_set: print(v) # 遍历“下标索引”和元素 for index, v in enumerate(my_set): print(index, v) # 集合、列表、元组 转换 a_set = {1, 2, 3} # 集合 b_list = list(a_set) # 列表 c_tuple = tuple(b_list) # 元组 d_set = set(c_tuple) # 集合 print(a_set, b_list, c_tuple, d_set) # {1, 2, 3} [1, 2, 3] (1, 2, 3) {1, 2, 3}
字典dict
my_dict = {'name': 'smart', 'age': 18, 'city': '上海'} # 通过健修改、添加值 my_dict['name'] = '刘海柱' # 根据字典的 key 获取对应的值 print(my_dict['name']) print(my_dict.get('name')) # 没有就None print(my_dict.get('name', value)) # 返回value # 通过key取出value print(my_dict.pop('city')) # 被取出的在原字典中就没了 my_dict_2 = {'a':0, 'b':1, 'c':2} print(len(my_dict_2)) print(max(my_dict_2)) print(min(my_dict_2)) # 通过key删除kv键值对 del my_dict_2['a'] print(my_dict_2) # 遍历key for key in my_dict: # for key in my_dict.keys(): print(key) # 遍历value for value in my_dict.values(): print(value) # 遍历key,value for (k,v) in my_dict.items(): print(k,v) # 遍历下标索引,key,value for i, (k, v) in enumerate(my_dict.items()): print(i, k, v) # 判断某个value是否在字典中 print('刘海柱' in my_dict.values()) print('刘海柱' not in my_dict.values()) # 判断某个key是否在字典中 print('name' in my_dict.keys()) print('name' not in my_dict.keys())
字符串str
name_1 = '职业法师刘海柱' name_2 = "雷电法王杨永信" # \n 换行 print(name_1 + '\n' + name_2) # 切片,左要右不要,步长减一,负数倒序 # 字符串[起始索引:结束索引:步长] 返回字符串 print(name_2[3]) print(name_2[2:3]) print(name_2[::-2]) print(name_2[2::2]) # 查找字符是否在字符串中,返回下标,不存在就返回-1 print(name_1.find('海')) print(name_1.find('海', 1, -1)) # 从下标1开始到最后一个字符 # 字符替换:原来的、新的、替换次数(默认不写则全部替换) print(name_2.replace('王', '神', 5)) # 返回新的字符串 # 指定分割字符串并丢弃,返回列表 ret_list = name_2.split('杨') print(ret_list) # 用字符串拼接列表中的每一个元素 print('杨'.join(ret_list)) my_int = 1234 # int # str函数的用法 your_str = str(my_int) # str print(type(your_str), your_str) # eval函数的用法 her_int = eval(your_str) # int print(type(her_int), her_int) # 字符串长度 print(len(name_2)) # 遍历字符串中每个字符 for v in name_2: print(v) # 遍历字符下标索引和值 for i,v in enumerate(name_2): print(i, v) # 判断字符是否在字符串中 print('王' in name_2) print('王' not in name_2)
04-函数
函数的作用:代码复用,区分代码逻辑功能
内置函数:Python自带可直接使用,如 type input print random.randint len sum max min format等
函数中的变量
变量作用域:指的是变量的作用范围,即变量在哪里可用,在哪里不可用)
局部变量:是函数内部定义的变量(包括函数的形式参数),其作用域只在函数内部有效,不能影响函数外部,除非使用关键字global 来声明全局变量。不同函数的局部变量可以同名,互不影响。
函数的参数
实参:在调用时给形参传入的具体值
位置参数(位置实参):函数调用时,按形参的位置,从左到右,依次传递实参,缺一不可,不需要指定形参名称
关键字参数(关键字实参):函数调用时,按照
形参名=值
的形式来传递实参,不必按照位置传递形参:声明函数(写函数)时的参数
普通形参
my_str
元祖不定长形参
*args
接收多个普通参数、参数名和值任意,在函数中以元组呈现缺省形参(默认)
my_int=666
字典不定长形参
**kwargs
接收多个普通参数、参数名和值任意,在函数中以字典呈现定义函数时、调用函数时,=左边的参数名都是形参,=右边的都是实参,有具体内容的都是实参
函数示例
# 石头剪刀布 # 导包声明,使用Python内置的random包 import random def caiQuanGame(nums, is_player_bool=True): """ 猜拳一次 1:石头; 2:剪刀; 3:布 电脑-玩家 = 共5种结果 0:平局 -1、2:电脑胜 1、-2:玩家胜 :param: is_player: 是否由电脑帮玩家猜拳, 默认True, 由玩家输入 nums: 游戏次数,在本函数中没用,传出函数 :return: (nums, result_str) :result_str: 平局! or 电脑胜! or 玩家胜! """ # 随机返回1、2、3其中一个数字 computer_int = random.randint(1,3) # if is_player_bool == 1: # if is_player_bool == True: # if is_player_bool is True: if is_player_bool: player_str = input('\n 1:石头 \n 2:剪刀 \n 3:布 \n玩家请输入:') # todo: ret = int(str) # 数字样子的字符串转换为数字 player_int = int(player_str) else: player_int = random.randint(1, 3) # 相减 ret = computer_int - player_int if ret == 0: result_str = '平局!' else: # 如果 -1或2 就是电脑胜;除此以外(1或-2;0已经在外层if中判断了)就是玩家胜 result_str = '电脑胜!' if ret == -1 or ret == 2 else '玩家胜!' return nums, result_str def main(): """程序主逻辑 :return: None 没有return关键字的函数 默认返回None """ nums = int(input('输入游戏次数:')) is_player = input('是否自动进行游戏?输入 "是" 或 "否":') is_player_bool = True if is_player == '是' else False i = 1 while True: # todo 调用猜拳函数 result = caiQuanGame(is_player_bool=is_player_bool, nums=nums) # 输出 caiQuanGame 函数的 第二个返回值 result_str print(result[1]) # return (nums, result_str) i += 1 if i > nums: break print('游戏结束') # 执行程序的主逻辑 main()
局部与全局变量
num = 10 # 声明全局变量 # 全局变量 def func1(): print('func1:', num) # 访问全局变量num func1() def func2(): # 这里相当于在函数内部定义了一个局部变量,也叫num,它的值为:10,它和全局变量没有关系 num = 20 # 声明局部变量 print('func2:', num) # 使用局部变量 func2() def func3(): # 需求:在 func3 函数调用时,修改全局变量 num,把它的值改为:10 # global一个关键字,这个关键字的作用是告诉 python 解释器,接下来使用的 num 是全局变量的 num # 下面这句代码叫 global num # 声明 全局变量 # 因为是全局变量,当func3函数被调用时,执行到这里时,全局的num都会修改 num = 30 # 修改 num的值 print('func3:此时刚刚修改了全局变量num的值') print('func3:', num) func3() print(num) func1() func2()
不定长参数
# 元组不定长参数,用1个 * 来声明,传入时是个元组 def func4(*args): print(type(args), args) return 111 ret = func4(1,3,5) # 字典不定长参数,用2个 ** 来声明,传入时是个字典 def func5(**kwargs): print(type(kwargs), kwargs) func5( name='彦祖', age=18, gender='男' ) # 函数不同形式的参数有顺序要求:普通参数,元组不定长参数,缺省参数,字典不定长参数 def func6(my_int, *args, name='德华', **kwargs): print(my_int) print(args) print(name) print(kwargs) func6(1, 2, 3, 4, name='柏芝', age=16, gender='女')
05-语法进阶
组包与拆包
# 组包:变量赋值时,= 右边有多个数据时,会自动包装为元组赋值给 = 左边的变量。 a = 1, 2, 3 print(type(a), a) # <class 'tuple'> (1, 2, 3) # 拆包:多个变量 = 容器数据,当变量数量等于容器长度时,容器中的每个元素会依次赋值给 = 号左边的变量。 # 注意:变量的个数必须和数据的个数相同。 a, b, c = (1, 2, 3) print(a, b, c) # 先组包、再拆包 a, b, c = 1, 2, 3 print(a, b, c) # 示例1:交换变量 a, b = 10, 20 print(f'交换之前:a={a},b={b}') #交换之前:a=10,b=20 a, b = b, a print(f'交换之后:a={a},b={b}') #交换之后:a=20,b=10 # 示例2:函数多个返回值 def func(): return 1, 2, 3 a, b, c = func() print(a, b, c) # 示例3:遍历字典 k v my_dict = {'name': '彦祖', 'age': 18} for index, (k, v) in enumerate(my_dict.items()): print(index, k, v)
可变与不可变类型
可变类型与不可变类型:在不改变内存地址的情况下,能否改变其中的数据,若能则是可变类型,若不能则是不可变类型。
可变类型
列表
字典
集合
不可变类型
数值类型(整型/浮点型/布尔)
字符串
元组
引用可以理解一种指向,python中=号赋值的本质就是建立或改变引用
-
引用、不可变类型、可变类型的推导过程如下
# a、b、c三个变量都引用(指向)了10 a = 10 b = a c = a print(id(a), id(b), id(c), id(10)) # id都一样 # a不再指向10,bc还指向10 a = 20 print(id(a), id(20), id(b), id(c)) # a变了,bc没变 # 函数调用传参 都是引用传递 id一致 num = 10001 print(id(num)) def func(my_num): print(id(my_num)) func(my_num=num) # 可变类型示例,两个list的id始终没有变化 my_list = [1, 2, 3] your_list = my_list print(id(my_list), id(your_list)) my_list[0] = 'hahaha' print(id(my_list), my_list) print(id(your_list), your_list)
深浅拷贝
list1 = [1, 2, [3, 4]] list2 = list1.copy() print("list1:", list1, id(list1)) print("list2:", list2, id(list2)) list1[2][0] = 5 print('修改了list1中的某个值') print("list1:", list1, id(list1)) print("list2:", list2, id(list2)) ret = """结论:这是【浅拷贝】! 通过copy函数,复制的对象的id发生了改变 原列表的值改变,新列表的值也跟着变 """ print(ret) from copy import deepcopy # 导包使用 deepcopy深拷贝函数 list1 = [1, 2, [3, 4]] list2 = deepcopy(list1) print("list1:", list1, id(list1)) print("list2:", list2, id(list2)) list1[2][0] = 5 print('修改了list1中的某个值') print("list1:", list1, id(list1)) print("list2:", list2, id(list2)) ret = """结论:这是【深拷贝】! 通过copy.deepcopy函数,复制的对象不光id发生改变 原列表的值改变,新列表的值不跟着变 原列表和新列表完全没有任何关联! """ print(ret)
range函数
range(11) range(1, 11) range(1, 11, 2) ret = range(1, 11, 2) # 从1到10,步长为2 print(type(ret), ret) # <class 'range'> range(1, 11, 2) print(list(ret)) # [1, 3, 5, 7, 9] # 可用for循环逐一遍历 for i in range(5): # range函数默认从0开始,默认步长为1 print(i)
列表推导式
# 列表推导式 print([i for i in range(5)]) print(list(range(5))) # 带判断的列表推导式 print( # 符合if条件的i,for i in range(10),if i除以2的余数为0 [i*2 for i in range(10) if i % 2 == 0] )
lambda表达式
"""lambda表达式:简单函数的简洁写法,又成为匿名函数 lambda表达式用法: 函数名 = lambda 参数1, 参数2, ... : 单行代码 函数名(参数1, 参数2, ...) 注意: 1.匿名函数中不能使用 while 循环、for 循环,只能编写单行的代码 2.匿名函数中返回结果不需要使用 return,单行代码的结果就是返回值 """ def func_sum(a, b): """计算a,b的和,返回结果""" return a + b # 使用 lambda 表达式定义一个上面的函数 lambda_sum = lambda a, b: a + b ret = lambda_sum(1, 3) print(ret) # 用法2,匿名函数这个名称的由来 print( (lambda a, b: a + b)(1, 3) # (lambda匿名函数)(参数) )
filter函数
"""filter函数:只干过滤选择的事儿!不干处理数据的事儿! 自定义过滤判断函数,可迭代对象的每个元素作为入参,只有返回True的该元素才会被保留 每个元素都作为自定义函数的入参,有多少个元素,自定义函数就会被执行多少次 用法: 新的可迭代对象 = filter(判断函数, 可迭代对象) print(list(新的可迭代对象)) """ # 过滤列表中的奇数 my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] def func3(i): return i % 2 == 1 my_iterable = filter(func3, my_list) newlist = list(my_iterable) print(newlist) # 可以使用lambda表达式 my_iterable = filter(lambda i: i%2==1, my_list) print(list(my_iterable)) # 判断函数返回 True 或 False !!! ret = func3(2) print(ret) ret = func3(3) print(ret) # 将某个列表中的所有数字全部变为正数,todo filter做不到! my_list = [-5, 3, -7, -99, 8, -9] def func1(i): # 将入参转为正数 ret = -i if i < 0 else i return ret print(func1(-9)) my_iterable = filter(func1, my_list) print(list(my_iterable)) # 无效! # 将某个列表中的所有正数取出,filter做的到! def func2(i): # todo 过滤判断函数返回的必须是True或False return i > 0 my_iterable = filter(func2, my_list) print(list(my_iterable)) print(list(filter(lambda i: i > 0, my_list)))
map函数
"""map函数:处理数据! 通过自定义函数,对可迭代对象的每一个元素分别进行操作,返回新的可迭代对象 new_可迭代对象 = map(处理每一个元素的函数, 可迭代对象) """ my_list = list(range(10)) print(my_list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ret = map(lambda i: i*i, my_list) print(list(ret)) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
reduce函数
"""reduce函数 通过自定义函数,先对第1、2元素进行操作,返回一个结果 再拿这个结果和第3个元素进行操作,直到得到最终的一个结果 结果 = reduce(处理函数, 可迭代对象) # 处理函数必须接收2个参数! [英] reduce v. 使...缩小、减少 """ from functools import reduce # reduce函数需要导包使用 ret = reduce(lambda x, y: x + y, list(range(10))) print(ret) # 45
06-操作文件
文件的读写
# 查看当前操作系统默认编码格式 import sys print(sys.getdefaultencoding()) # utf8 my_sys_default_encoding = sys.getdefaultencoding() print('【写】') with open('./111.txt', mode='w', encoding=my_sys_default_encoding) as f: f.write('职业法师刘海柱\n') # 写入不会换行! f.write('雷电法王杨永信') print('【读全部】') with open('./111.txt', mode='r', encoding=my_sys_default_encoding) as f: print(f.read(2)) # 读取规定数量的字符,并换行 print(f.read()) # 读取全部 print('【读一行】') with open('./111.txt', mode='r', encoding=my_sys_default_encoding) as f: # 每一行自带换行符,print再次换行,就出现了 输出结果有空行的现象 print(f.readline(3)) # 读取字符数,并换行 print(f.readline()) print('【逐行读】') with open('./111.txt', mode='r', encoding=my_sys_default_encoding) as f: # 每一行自带换行符,print再次换行,就出现了 输出结果有空行的现象 while True: ret = f.readline() if ret == '': # 如果读出来是空串,说明读完了 break print(ret) print('【读全部返回列表】') with open('./111.txt', mode='r', encoding=my_sys_default_encoding) as f: print(f.readlines()) # 返回list ['职业法师刘海柱\n', '雷电法王杨永信']
文件的访问模式
"""mode参数 文件的访问模式 r 只读,文件不存在就报错【默认模式】[常用] w 覆盖写,文件不存在就创建文件 a 追加写,文件不存在就创建文件(append,接着写)[常用] # b表示 byteString rb 二进制 只读,文件不存在就报错 wb 二进制 覆盖写,文件不存在就创建文件 ab 二进制 追加写,文件不存在就创建文件(append,接着写) r+ 读+覆盖写,文件不存在就报错 w+ 覆盖写+读,文件不存在就创建文件,注意:该模式打开文件瞬间清空文件内容! a+ 追加写+读,文件不存在就创建文件(append,接着写)[常用] """
文件的编码
"""encoding参数 文件的编码格式 windows操作系统下,open操作文件时,encoding参数默认为gbk; 较新版本的win操作系统默认编码方式用的却是utf8,这个时候就必须声明 encoding=‘utf8‘。 linux/mac操作系统下,open操作文件时,encoding参数默认为utf8。 """
相对和绝对路径
-
相对路径,所谓的相对,是相对代码运行的路径;不是相对当前代码文件的路径!
-
绝对路径,从根目录开始的,或从盘符开始描述的路径
# 相对路径 . # 一个点表示当前路径 .. # 两个点表示上一级路径 ../../a/b.txt # 当前代码运行路径上一级的上一级下的a目录下的b.txt ./c.txt # 当前代码运行路径下的c.txt文件 # 绝对路径 /a/b/c.txt # linux mac的绝对路径 D:\360MoveData\Users\hahage\Desktop\a.txt # win的绝对路径
os模块常用函数
import os """通过文件夹查看文件,pycharm侧边栏存在延迟""" with open('1.txt', mode='w', encoding='utf8') as f: f.write('大威天龙') # 查看指定的路径下有哪些文件和文件夹 print(os.listdir('./')) # ls # 文件重命名 os.rename('1.txt', 'haha.txt') print(os.listdir('./')) # 判断路径(可以是文件,也可以是文件夹)是否存在 print(os.path.exists('./haha.txt')) # 判断文件(不是文件夹)是否存在 print(os.path.isfile('./haha.txt')) # 删除文件 os.remove('haha.txt') print(os.listdir('./')) # 创建文件夹 os.mkdir('./haha') print(os.listdir('./')) # 删除文件夹 os.rmdir('./haha') print(os.listdir('./')) # 查看当前工作目录位置,即Python代码运行路径 print(os.getcwd()) # pwd # 改变工作目录位置 os.chdir('../') print(os.listdir('./'))
07-处理异常
# traceback.format_exc() # 完整的异常堆栈信息 import traceback try: print('语法错误是 sytanx error') print('异常错误是 exception error') print('a'+11) print(22222) print('a'+11) except Exception as e: # 仅输出异常提示信息 print(e) # traceback.format_exc() 完整的异常堆栈信息 print(traceback.format_exc()) else: print('如果没有发生异常就执行这里') finally: print('无论怎样都会执行这里') print('过分使用try except,会导致找不到问题所在位置,慎重使用') # 和循环判断with open一样,try.except也可以嵌套,他们可以互相嵌套 try: print(5/0) # 只捕捉专项异常 except ZeroDivisionError: print(traceback.format_exc()) print('【异常传递】') def foo(): print('foo start') print(num) # todo 报错的源头 print('foo end') def bar(): print('bar start') # 代码运行至此才会引发异常 foo() # todo 报错发生的导火索 print('bar end') try: bar() finally: print(traceback.format_exc())
08-模块和包
包 => 含有
__init__.py
文件的文件夹模块 => py文件
类 => class 【面向对象学习】
函数(方法)=> def
以上均不能以数字开头,也不能和python内置的一切重名
模块和包的使用
# from 模块 import 函数 from os import listdir ret = listdir() print(ret) # import 模块 import os ret = os.listdir() print(ret) # 用 as关键字 起别名 import os as winos ret = winos.listdir() print(ret) from os import listdir as win_listdir ret = win_listdir() print(ret)
__name__
属性
只有运行入口的py文件(模块)的
__name__
是__main__
,其他被引用的文件(模块)的__name__
是不带扩展名的文件名
下边的a.py和b.py两个文件,在同一目录中!
-
a.py
- 运行该文件
import os print(os.__name__) # 内置属性 模块名字 print(os.listdir.__name__) # 内置属性 函数名字 print(__name__) # 当前正在运行的模块名字 永远是 __main__ import b # 引用了b文件,b文件发生了运行 print(b.__name__) if __name__ == '__main__': print('aaaa') print(__name__)
-
b.py
print(__name__) if __name__ == '__main__': # 如果被其他py文件引用,这里将不会执行 # 因为被引用时,b.py的__name__是 b,而不是__main__ # 只有b.py作为主文件运行时,b的__name__才是__main__ print('bbbb') print(__name__)
__all__
属性
如果一个py文件(模块)中有
__all__
变量(list类型),当其他py文件(模块)使用from 模块名 import *
引用它时,只能导入这个列表中指定的内容
-
a.py
__all__ = ['foo', 'my_int'] my_int = 666 def foo(): return my_int def bar(): return 777
-
b.py
- 运行该文件
import traceback from a import * try: print(my_int) print(foo()) print(bar()) except: print(traceback.format_exc()) from a import bar print(bar())
模块的搜索路径
一切以被运行的python文件所在的路径为准,是工作路径,同时也是相对路径的起点
import sys print(sys.path) """sys.path可以说明: 运行py代码时,Python解释器会自动搜索要使用的模块 会自动向以下两个路径进行搜索: 1. 当前工作路径 2. Python虚拟环境路径 还可以手动添加导包环境路径: import sys sys.path.append('要导包的位置') 注意:自定义的一切变量、函数、类、模块、包, 都不要和python内置的一切重名! """
包是有特殊文件的文件夹
# 当我们使用一个包时,这个包目录下的__init__.py文件中的代码会自动执行。 # 包的 __init__ 文件中,也可以设置 __all__ 内置变量,限定 `from 包名 import *` 时默认导入的模块。 # 平时沟通时,包和模块的概念往往不区分 # 包和模块都存在内置的第三方的区别,第三方的就是玩家自己写的、非Python官方的 """三方包需要额外安装 安装命令: pip install 包名或模块名 -i https://pypi.tuna.tsinghua.edu/simple/ pip install 包名或模块名==版本号 pip install 包名或模块名 卸载命令:pip uninstall 包名或模块名 注意: 1. 安装第三方的包和模块是在 python 解释器安装目录的 Lib/site-packages 下面 2. python虚拟环境和默认环境 需要各自安装各自的三方包! 安装到指定的py虚拟环境下 /虚拟环境路径/python -m pip install 包名或模块名 默认安装到默认python下:pip install 包名或模块名 """
09-日志操作
日志的作用:自带时间,代码位置,信息分级可控,比print方便
日志基本分级:
debug 调试消息
info 普通消息
warning 警告消息
error 错误消息
critical 严重错误
python默认的日志包是logging,也有很多很成功的第三方包,比如loguru --
虚拟环境python -m pip install loguru
# import logger # pip install loguru from loguru import logger as log # 日志文件名称 # {time} loguru包会自动填写文件创建的时间 # xxxx-xx-xx_xx-xx-xxxxxx 年 月 日 时 分 秒 微秒6位 【秒后3位的是毫秒 毫秒后3位是微妙】 logfile_path_str = './loguru_test_{time}.log' # 日志保存,要先声明才有效 # log.add(logfile_path_str) log.add( sink=logfile_path_str, # 日志文件名 # 以下为可选参数 rotation='200KB', # 设定日志大小, 200k一个文件 compression='zip', # 设置压缩格式为zip retention='72h', # 每隔72小时清理一次日志 serialize=True, # 默认为False,普通日志;True 把日志改成json格式 encoding='utf8', # 声明日志文件的编码格式 # level='WARNING' # 日志文件只记录WARNING及更严重级别的日志 ) """ 1. 参数 rotation rotation='200KB', # 设定日志大小, 200k一个文件 rotation='14:00', # 每天中午14点创建新的日志文件 rotation='1 week', # 以周为单位,日志循环写入 2. 参数 compression='zip' # 支持多种压缩格式: gz bz2 xz lzma tar tar.gz tar.bz2 tar.xz zip 3. level='WARNING' # 日志文件记录的级别,顺序如下: DEBUG INFO SUCCESS WARNING ERROR CRITICAL """ # 自定义日志信息 log.debug('debug级别调试消息') log.success('成功调用') log.info('普通消息') # 常用 log.warning('警告消息') log.error('错误消息') log.critical('严重错误消息') # 记录错误异常 try: print(5/0) except: # 完整记录错误堆栈信息,显示内容和 traceback.format_exc() 一致 log.exception('错误消息') # 关闭控制台输出,且不写入日志文件 log.remove(handler_id=None) log.info('这个信息不回显示,111')
10-时间操作
-
time 内置模块
import time # 停止n秒 print(time.sleep(3)) # 1695539421.6926203秒 起始时间是1970年1月1日0点(unix纪元) print(time.time()) # 时间戳 1695539421.6926203 # print(time.ctime()) # Sun Sep 24 15:16:49 2023 print(time.strftime('%Y-%m-%d %H:%M:%S')) # 2023-09-24 15:20:24 # 时间戳转日期,time.strftime函数多加一个参数 print(time.localtime(时间戳)) # 不返回时间戳! # time.struct_time(tm_year=2023, tm_mon=10, tm_mday=7, tm_hour=12, tm_min=0, tm_sec=35, tm_wday=5, tm_yday=280, tm_isdst=0) print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(时间戳))) # 日期转时间戳 print(time.mktime( time.strptime( # 注意区别 strptime strftime time.strftime('%Y-%m-%d %H:%M:%S'), # 格式化的时间:2023-09-24 15:20:24 '%Y-%m-%d %H:%M:%S' # 指定格式 ) ))
-
datetime 内置模块
import datetime # 当前时间 print(datetime.datetime.now()) # 2023-09-24 15:13:57.999473 # 格式化输出时间 print(datetime.datetime.now().strftime('%Y-%m-%d')) # 2023-09-24 # 时间戳 1695540551.546279 print(datetime.datetime.now().timestamp()) # 输出年月日时分秒 print(datetime.datetime.now().day) print(datetime.datetime.now().year) print(datetime.datetime.now().minute) # 格式时间和时间戳互相转换 date_str = '2002-12-24' my_dt = datetime.datetime.strptime(date_str, '%Y-%m-%d') 时间戳 = my_dt.timestamp() print(时间戳) # 工作中 不要写中文命名! print(datetime.datetime.fromtimestamp(时间戳)) # 指定时间 dt = datetime.datetime(2002,12,24,22,40,59) print(dt) # 2002-12-24 22:40:59 print(dt.year) # 计算日期差 print(datetime.datetime.now() - dt) # 7578 days, 16:42:58.277457 # 计算某个时间点的多久之后、多久之前 # 工作中 不要写中文命名! 时间差 = datetime.timedelta(days=10, hours=3, minutes=30, seconds=30) print(datetime.datetime.now() - 时间差) # 2023-09-23 11:55:41.043847
11-json模块
# json是长得像字典的字符串,Python内置的json模块可以帮助我操作json import json my_dict = {'name': '职业法师刘海柱', 'age': 18} # json.dumps():dict转json字符串,dumps==dump String json_str = json.dumps(my_dict, ensure_ascii=False) # ensure_ascii=False 是否使用ascii编码,默认为True print(json_str, type(json_str)) # 双引号 print(my_dict, type(my_dict)) # 单引号 # json.loads():json字符串转dict,loads==load String new_dict = json.loads(json_str) print(new_dict, type(new_dict)) # json.dump() 将dict写入文件中,自动转换为json字符串 with open('./111.json', 'w', encoding='utf8') as f: json.dump(my_dict, f, ensure_ascii=False) # json.load() 将文件中json字符串读取出来,返回dict with open('./111.json', 'r', encoding='utf8') as f: new_dict2 = json.load(f) print(new_dict2, type(new_dict2))
12-面向对象
类和对象的关系:
类相当于图纸(抽象),对象相当于根据图纸制造的实物(具体)
每个对象必须有一个对应的类
类:
很多事物存在 相同的属性和行为(也叫方法),比如人有姓名年龄,能吃饭睡觉等等
描述 具有共同特征的事物的 抽象,称为 类 (class)
类包含两个组成部分:
属性(变量):比如姓名,年龄,身高,肤色等
方法(函数):比如吃饭,睡觉,飞行,歌唱等
对象:对象 是 类 的实例,是具体的实体
面向对象的特点
封装
将属性和方法放到一起封装成一个整体(定义类),然后通过实例化对象来使用
对属性和方法增加访问权限控制:公开权限、私有权限
继承
子类可以继承父类,子类继承父类之后,子类就拥有了父类中的属性和方法
重写:子类从父类继承过来的方法,不满足子类需要或不完全满足子类需要
私有和继承
多态:同一个代码,由于传入的实例对象的不同,最终代码的调用有不同的效果,这就叫多态
封装
类的定义和使用
房子和家具示例代码
#家具分不同的类型(名字),并占用不同的面积 #输出家具信息时,显示家具的类型和家具占用的面积 #房子有自己的地址和面积 #房子可以添加家具,如果房子的剩余面积可以容纳家具,则提示家具添加成功;否则提示添加失败 #输出房子信息时,可以显示房子的地址、面积、占用面积、剩余面积、显示包含的所有家具的类型 class Item(object): """家具类""" def __init__(self, name, area): self._name = name # 家具类型(名字) self._area = area # 家具占用面积 def __str__(self): return f'{self._name},面积{self._area}平米' class House: """房子类""" def __init__(self, addr, area): self._addr = addr # 地址 self._area = area # 总面积 self.use_area = 0 # 占用面积 self.free_area = self._area # 剩余面积初始等于总面积 self.item_list = [] # 家具列表 def __str__(self): ret = f"""房子坐落于{self._addr} 占地{self._area} 占用面积{self.free_area} 剩余面积{self.free_area} 目前家具有{self.item_list} """ return ret def add_item(self, item): """添加家具,计算并修改各种面积 item 是实例化的家具对象 有 家具类Item._area 属性 有 家具类Item._name 属性 """ # 修改占用面积 self.use_area = self.use_area + item._area # 修改剩余面积 self.free_area = self._area - self.use_area # 添加家具列表 self.item_list.append(item._name) # 实例化家具 sofa = Item(name='沙发', area=5) bed = Item('床', 4) desk = Item('书桌', 3) print(sofa, bed, desk) # 实例化房子 house = House(addr='金燕龙大院', area=20) print(house) # 向房子中添加家具 house.add_item(sofa) house.add_item(sofa) house.add_item(bed) house.add_item(desk) print(house)
del魔法方法
class Item: """家具类""" def __init__(self, name, area): self._name = name # 家具类型(名字) self._area = area # 家具占用面积 def __str__(self): return f'{self._name},面积{self._area}平米' def __del__(self): # 当删除对象时,此方法会被自动调用执行 print(f'丢弃了家具{self._name}') sofa = Item('沙发', 5) # 手动删除实例对象,自动执行__del__函数 del sofa # 如果不手动删除,程序运行结束前会自动删除 try: # 类还在,对象却没了! print(Item) print(sofa) except Exception as e: print(e)
公开和私有权限
-
公开属性、公开方法:随便调用
-
私有属性、私有方法:
-
只能在类定义的内部调用
-
以两个下划线开头
__
的都是私有权限
-
class Women: """""" def __init__(self, name): self.name = name # 公开属性 self.__age = 18 # 私有属性 def func1(self): # 公开方法 print(self.name) print(self.__age) # 可以调用 print(self.__func2()) # 可以调用 def __func2(self): # 私有方法 print(self.name) print(self.__age) lady = Women('lady gaga') lady.func1() # lady.__func2() # 不可以调用 # print(lady.__age) # 不可以调用 # 实例对象._类名__属性或方法名 可强行突破! print(lady._Women__age) # 强行调用私有属性 lady._Women__func2() # 强行调用私有方法
继承
类的继承:在面向对象编程中,子类可以直接继承父类,从而使子类直接具备父类的能力(属性和方法)【代码复用】
继承作用:解决代码重用问题,提高开发效率
注意
站在父类的角度来看,父类派生出子类
站在子类的角度来看,子类继承于父类
父类也叫基类,子类也叫派生类
object 是 python 中所有类的父类
多继承
class SmallDog(object): def eat(self): print('小口吃东西') def sleep(self): print('小憩一会') class BigDog(object): def drink(self): print('大口喝水') def sleep(self): print('呼呼大睡') # 多继承 默认调用先继承的那个父类中的同名方法 # SuperDog 类定义时同时继承了 SmallDog 和 BigDog class SuperDog(BigDog, SmallDog): pass # 创建一个 SuperDog 对象 sd1 = SuperDog() # SuperDog 从 SmallDog 继承了 eat 方法 sd1.eat() # SuperDog 从 BigDog 继承了 drink 方法 sd1.drink() # 默认调用先继承的那个父类中的同名方法 sd1.sleep()
继承多层传递
# 爷爷类 class Animal(object): """动物类""" def eat(self): print('吃东西') # 爸爸类 class Dog(Animal): """狗类""" def drink(self): print('喝水') # 儿子类 class SuperDog(Dog): pass # 创建一个 SuperDog 对象 sd1 = SuperDog() sd1.eat() sd1.drink()
重写父类方法
重写父类(包括爷爷类及以上)方法:
从父类继承的方法不能满足子类的需要,为了拓展功能而重新定义了同名函数
重写形式:
在子类中定义了一个和父类(包括爷爷类及以上)同名的方法(参数也一样),即为对父类(包括爷爷类及以上)的方法重写
重写之后子类调用同名方法,默认只会调用子类的
类继承存在顺序链:
定义类名时从左到右的顺序,左边是右边的子类
class SuperDog(SmallDog, BigDog):
这个继承顺序为继承顺序:SuperDog->SmallDog->BigDog
子类调用父类被重写方法:在子类方法中还想调用父类的同名方法。可以使用如下方式:
父类名.同名方法(self, 形参1, ……)
super(顺序链目标类左边的类名, self).同名方法(...)
class SmallDog(object): def eat(self): print('吃小东西') class BigDog(object): def eat(self): print('啃大骨头') class SuperDog(SmallDog, BigDog): # todo 继承顺序:SuperDog->SmallDog->BigDog def eat(self): print('--方式1:父类名.同名方法(self, ...)--') # 需求1:调用 SmallDog 父类的 eat 方法 SmallDog.eat(self) # 需求2:调用 BigDog 父类的 eat 方法 BigDog.eat(self) print('--方式2:super(顺序链目标类左边的类名, self).同名方法(...)--') # 需求1:调用 SmallDog 父类的 eat 方法 super(SuperDog, self).eat() # 需求2:调用 BigDog 父类的 eat 方法 super(SmallDog, self).eat() # 本质:super(顺序链上目标父类左边的子类, self).目标父类的同名方法() print('--方式3:super().同名方法(...)--') # 需求1:调用 SmallDog 父类的 eat 方法 super().eat() # 与super(SuperDog, self).eat()相同 # 类的继承顺序链:在python中,一个类可以继承多个类, # 而且父类还可能有父类,对于这种情况,类的继承是有一个先后顺序, # 这个顺序就叫继承顺序链。 # 如何查看一个类的继承顺序链:类名.__mro__ print(SuperDog.__mro__) # 创建一个 SuperDog 对象 sd1 = SuperDog() sd1.eat()
继承链
class A: def func(self): print('A类中的func函数') class C(A): def func(self): super().func() print('C类中的func函数') class B(A): # todo 在B看来,自己的爹永远是A def func(self): super().func() print('B类中的func函数') class D(B, C): # todo 在D看来,B的爹是C!因为D声明的继承链是 D->B->C # todo 但这不影响在B的领域,B的爹始终A! def func(self): super().func() print('D类中的func函数') print('在D看来,B的爹是C') obj = D() obj.func() print('在B看来,B的爹是A') obj_b = B() obj_b.func() # 输出如下 在D看来,B的爹是C A类中的func函数 C类中的func函数 B类中的func函数 D类中的func函数 在B看来,B的爹是A A类中的func函数 B类中的func函数
禁止私有继承
# 父类中的私有属性和方法不能被子类直接继承 # 在父类中提供公开方法,该方法中进行私有属性和方法的访问 class Animal(object): """动物类""" def __init__(self, _name, _age): self.name = _name self.__age = _age # 私有属性 # 私有方法 def __pee(self): """pee:撒尿""" print('上厕所嘘嘘') def show_info(self): print(f'名字:{self.name},年龄:{self.__age}') def sleep(self): # 睡觉撒尿 self.__pee() print('睡觉了💤') class Dog(Animal): """狗类""" def test(self): # Animal 中的私有属性和方法不能被 Dog 类继承 # print(self.__age) # self.__pee() self.show_info() self.sleep() # 创建一个 Dog 对象 dog1 = Dog('旺财', 2) dog1.test()
多态
同一个代码,由于传入实例对象的不同,最终有不同的调用效果!
class PayClass(object): """支付类""" def pay(self): """付款""" pass def refund(self): """退款""" pass class Alipay(PayClass): """支付宝类""" def pay(self): print('支付宝付款') def refund(self): print('支付宝退款') class WeChat(PayClass): """微信支付类""" def pay(self): print('微信付款') def refund(self): print('微信退款') def func(obj): # 于传入的实例对象的不同 # 最终产生了不同的调用(执行)效果 obj.pay() # 什么是多态:同一个代码,由于传入实例对象的不同,最终有不同的调用效果! ap1 = Alipay() wc1 = WeChat() func(ap1) func(wc1) # Python是动态语言,站在代码写手的角度, # 本身就是多态,不存在非多态的情况 def add(a, b): return a + b res = add(1, 2) print(res) # 3 res = add('hello', 'world') print(res) # helloworld
封装进阶
类属性与实例属性
class Dog(object): # 记录一共创建了多少个Dog对象 count = 0 # 类属性 def __init__(self, _name, _age): self.name = _name # 实例属性 self.age = _age # 实例属性 self.sum = 0 # 实例属性 self.count = 666 # 实例属性 # self就是实例对象! # 只要 __init__ 被调用,就说明创建了 Dog 对象 Dog.count += 1 # 类属性的调用 dog1 = Dog('小黑', 2) print(Dog.count) # 1 print(dog1.count) # 666 dog2 = Dog('大黄', 3) print(Dog.count) # 2 print(dog2.count) # 666 dog3 = Dog('小白', 1) print(Dog.count) # 3 print(dog3.count) # 666
实例方法 类方法 静态方法
class Dog(object): count = 0 # 类属性 def __init__(self, _name, _age): self.name = _name # 实例属性 self.age = _age # 实例属性 Dog.count += 1 # 实例化一次就自增 1 # 实例方法:只能通过实例对象进行调用 def show_info(self): print(f'我的名字:{self.name}, 年龄:{self.age}') # 需求:提供一个显示一共有多少只狗的方法 # 类方法:使用@classmethod标记,通过类名调用 @classmethod def show_dogs_count(cls): print(f'现在一共有{cls.count}只狗') # 静态方法:使用@staticmethod声明,逻辑上属于类,但是和类“没有关系” # 用不到类中的任何数据,可以没有参数。 @staticmethod def readme(): print('温馨提示:交易造成杀害,领养代替买卖') dog1 = Dog('小黑', 2) dog2 = Dog('大黄', 3) dog1.show_info() # 实例方法调用 dog2.show_info() # 实例方法调用 Dog.show_dogs_count() # 类方法调用 Dog.readme() # 静态方法调用
13-闭包装饰器
闭包
-
函数嵌套(外部函数中定义了一个内部函数)
-
外部函数返回了内部函数
-
内部函数使用了外部函数的变量(包括外部函数的参数)
def func_outer(): # 定义一个全局变量 count,来记录 sub 函数的调用次数 count = 0 def sub(a, b): """计算两个数之差""" nonlocal count count += 1 # count = count + 1 print(f'第{count}次调用该函数') return a - b return sub # 注意:这里调用外部函数,是为了拿到内部函数对象 func = func_outer() print(func) func(1, 2) func(2, 3) func(3, 5)
装饰器
import time # 装饰器函数 def get_time(func): def wrapper(num): # todo: wrapper函数的参数 func函数的参数 s1 = time.time() # todo:调用原始函数,调用时可以先获取原始函数的返回值 result = func(num) s2 = time.time() print('执行时间:', s2 - s1) # todo:将原始函数的返回值再返回 return result return wrapper @get_time def func1(num): _sum = 0 for i in range(1, num+1): _sum += i return _sum res = func1(100) print(res)
通用装饰器
# 编写一个通用的装饰器,计算函数的执行时间,要求可以装饰任意函数(带任何参数或返回值) import time def get_time(func): # todo:给装饰器的内部函数,设置两种不定长形参 # wrapper函数 其实就是 new_func 新的func函数(增加了额外功能!) def wrapper(*args, **kwargs): # todo: 增加代码,扩展功能 s1 = time.time() # todo:将内部函数接收的参数,拆解原封不动的传递给func,同时接收func返回值 result = func(*args, **kwargs) # todo:增加代码,扩展功能 s2 = time.time() print(f'函数的执行时间为:{s2-s1}') # todo:将func的返回值,再进行返回 return result return wrapper # 语法糖 @get_time def func1(): """func1函数无参数,也无返回值""" _sum = 0 for i in range(1000000): _sum += i return _sum @get_time def func2(m, n): """计算m-n之间的数字和,func2函数有两个参数,也有返回值""" result = 0 # 遍历计算 m-n 之间的数字和 for i in range(m, n + 1): result += i # 返回计算的结果 return result result1 = func1() print(result1) result2 = func2(1, 1000000) print(result2)
带参装饰器
""" @装饰器(参数) 本质:带参装饰器的本质,是在普通的装饰器的外面,又包了一层函数 """ import time """普通装饰器 2层函数嵌套,无需最外层的函数包裹 装饰器带参数,就在2层基础上,再加一层,专门接收装饰器的参数 """ def func_outer(float_decimals): """接收装饰器的参数""" """返回 下一层函数(名字)""" def get_time(func): """接收被装饰的函数""" """返回 内层函数(名字)""" def wrapper(*args, **kwargs): """接收被装饰函数的参数""" """对被装饰的函数额外加功能,会用到外层函数的参数""" """运行被装饰的函数""" """返回 被装饰函数运行的结果""" s1 = time.time() result = func(*args, **kwargs) s2 = time.time() # 控制小数的位数 ret = round(s2-s1, float_decimals) print(f'函数的执行时间为:{ret}秒') return result return wrapper return get_time @func_outer(float_decimals=3) # 控制输出的小数位数 def func1(): """func1函数无参数,也无返回值""" _sum = 0 for i in range(1000000): _sum += i return _sum print(func1())
14-多进程多线程
并发与并行
并发:在一段时间内快速交替去执行多个任务(多线程)
并行:在一段时间内真正的同时一起执行多个任务(多进程)
进程(Process)
是操作系统进行资源分配的基本单位
进程可以有一个或多个子进程
最原始的父进程是由操作系统提供的
线程(Thread)
是CPU进行调度的基本单位
线程可以有一个或多个子线程
线程是由进程主动创建出来的,创建第一次创建子线程时才会出现主线程
线程的资源共享问题(只存在于低版本的Python解释器比如3.6.5,3.10已解决):当多个线程同时操作同一个共享的全局变量时,可能会造成错误的结果,解决办法如下
线程同步:保证同一时刻只能有一个线程去操作共享资源(全局变量)
线程等待
thread.join()
:
让一个线程完全执行结束,再去执行另一个线程
缺点:一个执行完再执行另一个,和单任务几乎没有区别
互斥锁:
多个线程去抢同一把"锁",threading.Lock()抢到锁的线程执行,没抢到锁的线程会阻塞等待。
缺点:虽然保障程序执行的多任务,如果频繁的加锁、释放锁会额外增加执行的时间消耗
从场景下手:不用多线程做累加count操作,只做append操作!
进程线程对比
进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位。
线程不能够独立执行,必须依存在进程中。
创建进程的资源开销要比创建线程的资源开销要大。
进程之间不共享全局变量,线程之间共享全局变量,但是在低版本的Python中要注意线程资源竞争的问题。
进程稳定性高,适合计算密集型任务;线程适合IO密集型任务
目前Python多线程不能利用CPU多核心优势,想利用CPU多核心的优势,Python只能采用多进程
多进程
多进程示例
import time import os import multiprocessing # os.getpid():process id,获取进程的编号 # os.getppid():parent process id,获取父进程编号 # 跳舞函数 def dance(): print(f'dance进程的编号:{os.getpid()},父进程编号:{os.getppid()}') for i in range(5): print('跳舞中...') # 休眠1秒钟 time.sleep(1) # 唱歌函数 def sing(): print(f'sing进程的编号:{os.getpid()},父进程编号:{os.getppid()}') for i in range(5): print('唱歌中...') # 休眠1秒钟 time.sleep(1) if __name__ == '__main__': # 最原始的父进程是由操作系统提供的 print(f'主进程的编号为:{os.getpid()},父进程编号:{os.getppid()}') # 创建两个进程,一个执行 dance 函数,另一个执行 sing 函数 dance_process = multiprocessing.Process(target=dance) sing_process = multiprocessing.Process(target=sing) # 启动进程 dance_process.start() sing_process.start()
多进程执行带有参数的任务
import multiprocessing import time # 带有参数的任务(函数) def task(count): for i in range(count): print('任务执行中...') time.sleep(0.2) else: print('任务执行完成') if __name__ == '__main__': # 传参方式1 args=(参数值1, ...) # task_process = multiprocessing.Process(target=task, args=(3,)) # 传参方式2 kwargs={'形参字符串1': 值1, '形参字符串2': 值2, ...} task_process = multiprocessing.Process(target=task, kwargs={'count': 5}) # 启动进程 task_process.start()
进程之间不共享变量
import multiprocessing import time # 定义全局变量 g_list = [] # 添加数据的函数 def add_data(): for i in range(5): g_list.append(i) print('add:', i) time.sleep(0.2) print('add:', g_list) # 读取数据的函数 def read_data(): print('read:', g_list) if __name__ == '__main__': # 创建添加数据的子进程 add_data_process = multiprocessing.Process(target=add_data) # 创建读取数据的子进程 read_data_process = multiprocessing.Process(target=read_data) # 启动添加数据子进程 add_data_process.start() # 阻塞等待:主进程等待 add_data_process 执行完成,再向下继续执行 add_data_process.join() # 启动读取数据子进程 read_data_process.start() # 主进程读取数据 print('main:', g_list) # 主进程延时 1s time.sleep(1) print('主进程结束!')
子进程设为守护进程
主进程结束,设为守护进程的子进程主动GG
import multiprocessing import time def task(): for i in range(10): print('任务执行中...') time.sleep(0.5) if __name__ == '__main__': # 创建子进程并启动 sub_process = multiprocessing.Process(target=task) # TODO:设置子进程为守护进程 sub_process.daemon = True sub_process.start() # 主进程延时 1s time.sleep(1) print('主进程结束!')
主进程终止子进程
子进程被动GG
import multiprocessing import time # 任务函数 def task(): for i in range(10): print('任务执行中...') time.sleep(0.5) if __name__ == '__main__': # 创建子进程并启动 sub_process = multiprocessing.Process(target=task) sub_process.start() # 主进程延时 1s time.sleep(1) print('主进程结束!') # TODO: 终止子进程 sub_process.terminate()
线程
多线程示例
import time import threading # 跳舞函数 def dance(num): for i in range(num): print('跳舞中...') time.sleep(1) # 唱歌函数 def sing(num): for i in range(num): print('唱歌中...') time.sleep(1) if __name__ == '__main__': # 创建两个线程,分别执行 dance 和 sing dance_thread = threading.Thread(target=dance, args=(5,)) sing_thread = threading.Thread(target=sing, kwargs={'num':5}) # 启动线程 dance_thread.start() sing_thread.start()
线程共用全局变量
import threading import time # 定义全局变量 g_list = [] # 添加数据的函数 def add_data(): for i in range(5): g_list.append(i) print('add:', i) time.sleep(0.2) print('add:', g_list) # 读取数据的函数 def read_data(): print('read:', g_list) if __name__ == '__main__': # 创建添加数据的子线程 add_data_thread = threading.Thread(target=add_data) # 创建读取数据的子线程 read_data_thread = threading.Thread(target=read_data) # 启动添加数据子线程 add_data_thread.start() # 阻塞等待:主线程等待 add_data_thread 执行完成,再向下继续执行 add_data_thread.join() # 启动读取数据子线程 read_data_thread.start() # 阻塞等待:主线程等待 read_data_thread 执行完成,再向下继续执行 read_data_thread.join() print('main:', g_list)
线程互斥锁
注释lock锁相关代码,并使用 低版本的Python解释器(python3.6.5) 才能看到线程资源安全问题的效果!Python 3.10 已经解决了该问题!
# 互斥锁:多个线程去抢同一把"锁",抢到锁的线程执行,没抢到锁的线程会阻塞等待 import threading # 定义全局变量 g_num = 0 # 创建一个多线程互斥锁 lock = threading.Lock() def sum_num1(): global g_num # 循环一次给全局变量加1 for i in range(1000000): # 抢到锁,代码可以继续向下执行,否则就会阻塞等待 lock.acquire() # 抢锁 g_num += 1 lock.release() # 释放锁 print('sum1:', g_num) def sum_num2(): global g_num # 循环一次给全局变量加1 for i in range(1000000): # 抢到锁,代码可以继续向下执行,否则就会阻塞等待 lock.acquire() # 抢锁 g_num += 1 lock.release() # 释放锁 print('sum2:', g_num) if __name__ == '__main__': # 创建两个线程 first_thread = threading.Thread(target=sum_num1) second_thread = threading.Thread(target=sum_num2) # 启动两个线程 first_thread.start() second_thread.start() # 阻塞等待:主线程等待子线程结束再向下运行 first_thread.join() second_thread.join() print(g_num)
15-网络编程
IP地址
IPv4
IPv6
查看本机的IP地址
win
ipconfig
linux
ifconfig
ping命令
ping www.baidu
查看是否能连通指定的网站
ping 192.168.1.222
查看是否能连通指定的IPPort端口
0-65535
TCP/IP协议
传输数据之前要建立连接,通过三次握手建立:
客户端 --> 服务端 ,SYN 客户端告诉服务端我是谁
服务端 --> 客户端 , ACK + SYN
服务端告诉客户端我收到了你的SYN(ACK)
服务端告诉客户端我是谁 (SYN)
客户端 --> 服务端 ,ACK
服务端告诉客户端我收到了你的SYN ,同时确认你收到了我的SYN(ACK)
开始传输数据 报文+内容
报文类似元数据,描述数据从哪来、到哪去,数据大小、数据类型等
内容:byteString类型,即bytes
-
bytes和str类型的互相转换
a = '哈萨克斯坦@#$%^&*(abc' # str -> bytes类型(byte String) # 按照utf8的格式,将str转为byteString类型 a_bytes = a.encode() # 默认utf8 print(a_bytes) # bytes类型 -> str a = a_bytes.decode() # 默认utf8 print(a) """ b'\xe5' bytes 字节类型字符串 只是为了方便网络通讯 16进制数字来表述符号 【b】 表示bytes 【\xe5】 表示后边两个字符是16进制数字 """ # 按照gbk的格式,将str转为byteString类型 b_bytes = a.encode('gbk') print(b_bytes) b = b_bytes.decode('gbk') # bytes类型 -> str print(b) # bytes数据一定可以转换为字符串吗???不一定(比如:图片、视频、音频等)
-
TCP服务端代码
跨服务器测试时:
服务端代码和客户端代码必须在同一个网段之内!
服务端绑定ip时,请使用
0.0.0.0
;对应的客户端代码要连接的ip写服务端的IP
"""TCP 服务端""" import socket # ① 创建一个服务端socket套接字,负责接收客户端的请求(门迎) # socket.AF_INET:使用IPV4的地址 # socket.SOCK_STREAM:使用TCP协议 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # ② 绑定服务端的ip地址和端口号 # ('ip地址', 端口号) # server_socket.bind(('127.0.0.1', 8080)) server_socket.bind(('192.168.25.76', 8080)) # ③ 设置服务端进入监听状态 # 服务端同一时间支持多少个客户端向它发起连接请求 server_socket.listen(128) # ④ 服务端等待客户端进行连接 print('服务端等待接收客户端的请求...') # 没有客户端来连接服务端时,accept方法会阻塞等到,直到有客户端来连接,accept才会返回 # service_client_socket:也是一个 socket 对象,负责和对应的客户端进行通信(服务员) # ip_port:是一个元祖,包含的是客户端的ip和port service_client_socket, ip_port = server_socket.accept() print(f'服务端来自{ip_port}客户端的连接...') # ⑤ 服务端接收客户端发送的数据 # 如果客户端没有给服务端发送消息,recv也会阻塞等待 recv_msg = service_client_socket.recv(1024) # bytes print(f'接收到来自客户端的消息:{recv_msg.decode()}') # ⑥ 服务端给客户端回应数据 send_msg = input('请输入给客户端回应的消息:') # str service_client_socket.send(send_msg.encode()) # ⑦ 关闭服务端的 socket service_client_socket.close() server_socket.close()
-
TCP客户端代码
"""TCP客户端""" import socket # ① 创建一个客户端的 socket 套接字 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # ② 通过客户端 socket 连接服务端 client_socket.connect(('192.168.25.76', 8080)) # ③ 发送消息给服务端 send_msg = input('请输入发送给服务端的消息:') client_socket.send(send_msg.encode()) # ④ 接收服务端回应的消息 recv_msg = client_socket.recv(1024) # bytes print(f'接收到来自服务端的消息:{recv_msg.decode()}') # ⑤ 关闭客户端 socket client_socket.close()
16-正则表达式
re正则表达式,一种专门用来匹配目标字符串的规则
正则语法 描述 . 匹配任意1个字符,除了 \n \d 匹配1位数字,即0-9 \D 匹配1位非数字 \s 匹配1位空白符:空格、Tab \S 匹配1位非空白符 \w 匹配1位非特殊字符:即a-z、A-Z、0-9、_、汉字 \W 匹配1位特殊字符 [列举字符] 匹配1个[ ]中列举的字符:[a-z]表示匹配1个小写英文字符 * 匹配出现0次或任意次的一个字符:\d* 表示 0个或任意个连续的数字 + 匹配出现1次或任意次的一个字符:\d+ 表示 1个或任意个连续的数字 ? 匹配出现1次或0次的一个字符:\d+? 表示 1个数字 {m} 匹配出现m次的字符:\d{3} 表示 连续3个数字 {m,n} 匹配出现从m到n次的字符:\d{2,5} 表示连续2到5个数字 ^ 匹配字符串开头:^a 表示以a开头的 $ 匹配字符串结尾 :b$ 表示以b结尾 [^指定字符] 匹配除了指定字符以外的所有字符 [^\d]+
表示除了数字以外的字符| 匹配左右任意一个正则表达式 \d+|\W+
表示数字或特殊字符
re.match()
从头匹配一个,无则None
"""match函数:尝试从字符串起始位置根据正则表达式匹配一个结果 re.match(pattern正则表达式, string目标字符串) 1.如果不能从起始位置匹配成功,则返回None; 2.如果能从起始位置匹配成功,则返回一个匹配的对象 """ import re my_str = 'abc_123_DFG_456_abc' # 匹配字符串bc(注:从头开始) res = re.match('bc', my_str) print(res) # None # 匹配字符串abc(注:从头开始) res = re.match('abc', my_str) print(res) # 匹配成功,返回一个 Match 对象 # Match对象.group():获取匹配的内容 print(res.group()) print('-----------')
re.search()
不从头匹配返回一个,无则None
"""search函数:根据正则表达式扫描整个字符串,并返回第一个成功的匹配 re.search(pattern, string, flags=0) 1. 如果不能匹配成功,则返回None; 2. 如果能匹配成功,则返回一个匹配对象 """ import re my_str = 'abc_123_DFG_456_abc' # 匹配连续的3位数字 # \d{3} res = re.search(r'\d{3}', my_str) print(res.group()) res = re.search(r'bc', my_str) print(res.group())
re.findall()
不从头匹配,用list返回所有
"""findall函数:根据正则表达式扫描整个字符串,并返回所有能成功匹配的子串 re.findall(pattern, string, flags=0) 1. 如果不能匹配成功,则返回一个空列表; 2. 如果能匹配成功,则返回包含所有匹配子串的列表 """ import re my_str = 'abc_123_DFG_456_abc' # 匹配字符串中的所有连续的3位数字 res = re.findall(r'\d{3}', my_str) print(res)
re分组
import re """ 示例1:正则匹配分组操作 语法:(正则表达式) """ # 匹配手机号前3、中4、后4位数据 my_str = '13155667788' # 131 5566 7788 # \d{3}\d{4}\d{4} # (\d{3})(\d{4})(\d{4}) res = re.match(r'(\d{3})(\d{4})(\d{4})', my_str) print(res) print(res.group()) # 完整的匹配结果 # Match对象.group(组序号) print(res.group(1)) # '131' print(res.group(2)) # '5566' print(res.group(3)) # '7788' print('--------------') """ 示例2:给正则分组起别名 语法:(?P<分组别名>正则表达式) """ # 需求:使用正则提取出 my_str 字符串中的 `传智播客` 文本 my_str = '<div><a href="https://www.itcast" target="_blank">传智播客</a><p>Python</p></div>' res = re.search('<a.*>(?P<text>.*)</a>', my_str) print(res) print(res.group()) # 完整匹配结果 print(res.group(1)) # 根据组序号取匹配的数据 print(res.group('text')) # 根据组别名取匹配的数据 """ 示例3:引用正则分组 语法:(?P<分组别名>正则表达式).*(?P=分组别名) """ import re # 需求: 找到字符串里反复出现3次的连续的数字 my_str = 'a123jkfjkfjg123' # ==> None my_str = '123aq123a123' # ==> 123 my_str = '123123123' # ==> 123 my_str = '123 123123' # ==> 123 res = re.match(r'(?P<num>\d+)\D*(?P=num)\D*(?P=num)$', my_str) if res: print('匹配成功') print(res.group(1)) print(res.group('num')) else: print('匹配失败')
re匹配修饰符
改规则
import re """ re.I:匹配时不区分大小写 re.M:多行匹配,影响 ^ 和 $ re.S:影响 . 符号,设置之后,.符号就能匹配\n了 """ # re.I:匹配时不区分字母的大小写 my_str = 'aB' res = re.match('ab', my_str, flags=re.I) print(res.group()) print('----------------') # re.M:开启多行匹配模式,把每一行字符串,当作一个独立的字符串进行匹配 my_str = 'aabb\nbbcc' res = re.findall('^[a-z]{4}$', my_str, flags=re.M) print(res) res = re.findall('^[a-z]{4}$', my_str) print(res) res = re.findall('[a-z]{4}', '11aabb') print(res) res = re.findall('^[a-z]{4}$', '11aabb') # 被匹配的字符串必须以字母开头以字母结尾 print(res) print('----------------') # re.S:让 . 也能匹配\n my_str = '\nabc' res = re.match('.', my_str, flags=re.S) print(res) # 多模式:flags=re.S|re.M|re.I my_str = '1111\nabc' res = re.findall('.', my_str, flags=re.S|re.M|re.I) print(res)
re贪婪非贪婪
import re """ 贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 正则中的量词包括:{m,n}、?、*和+,这些量词默认都是贪婪模式的匹配 可以在这些量词后面加?将其变为非贪婪模式。 """ my_str = '<div>test1</div><div>test2</div>' # 贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 re_obj = re.match('<div>.*</div>', my_str) print(re_obj.group()) # 获取整个正则表达式匹配的内容 print('----') # 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 re_obj = re.match('<div>.*?</div>', my_str) print(re_obj.group()) # 获取整个正则表达式匹配的内容 # \d{2,5}? == \d{2} != \d{2,5} my_str = '221324324324242' re_obj = re.match('\d{2,5}?', my_str) print(re_obj.group()) re_obj = re.match('\d{2,5}', my_str) print(re_obj.group()) re_obj = re.match('\d{2}', my_str) print(re_obj.group())
re切割和替换
import re # re.split(pattern, string, maxsplit, flags) # 作用:对字符串进行分割 # 过程:先使用正则对字符串进行匹配,正则匹配到的内容作为分割符,对字符串进行分割 str1 = 'hello-python_hive' res1 = re.split('[-_]', str1) print(res1) # ['hello', 'python', 'hive'] # re.sub(pattern, repl, string, count, flags) # 作用:对字符串中的内容进行替换 # 过程:先使用正则对字符串进行匹配,然后将匹配到的内容进行替换,返回替换之后的新字符串 str2 = 'hello-python_hive' # 'hello:python:hive' res2 = re.sub('[-_]', ':', str2) print(res2) # hello:python:hive
17-pymysql模块
查询
""" pymysql获取查询结果 学习目标:常握 pymysql 获取SQL查询结果 """ # ① 导入模块 import pymysql # pip install pymysql # ② 创建连接 conn = pymysql.connect(host='192.168.88.131', port=3306, user='root', password='itcast', database='test', charset='utf8') # ③ 创建游标 cursor = conn.cursor() # ④ 执行SQL sql = 'select * from students' num = cursor.execute(sql) # 返回行数 # cursor.rownumber:记录当前获取的行号 print(f'受影响的行数:{num}') # 获取 sql 查询的结果 # 返回2条数据 res = cursor.fetchmany(2) print(res) # 接着 返回1条数据 res = cursor.fetchone() print(res) # 接着 返回全部数据 res = cursor.fetchall() print(res) # 接着 返回一条数据,但没有了,只能是None res = cursor.fetchone() print(res) print(cursor.rownumber) # 当前行数 # ⑤ 关闭游标 cursor.close() # ⑥ 关闭连接 conn.close()
增删改
""" pmysql增、删、改操作 学习目标:掌握 pymysql 对 mysql 数据库进行增、删、改操作 """ # ① 导入模块 import pymysql # ② 创建连接 conn = pymysql.connect(host='192.168.88.131', port=3306, user='root', password='itcast', database='test', charset='utf8') # ③ 创建游标 cursor = conn.cursor() # 开启事务 conn.begin() # ④ 执行SQL insert_sql = 'insert into students values("Tom", 25, "male", 2.9)' cursor.execute(insert_sql) select_sql = 'select * from students' cursor.execute(select_sql) # 获取查询的结果 res = cursor.fetchall() print(res) # 提交事务 connmit() # ⑤ 关闭游标 cursor.close() # ⑥ 关闭连接 conn.close() # DELETE FROM students WHERE name = 'Tom'; # SELECT * FROM students;
版权声明:本文标题:python基础语法 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1730030841a1219968.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论