设置环境变量是为了在CMD命令中或是编程时可任意调用Python命令,不会提示出错。
注:安装Python和Pycharm的时候,记得把Path选项打上勾,就会自动配置好环境变量了。
命令:
交互式并不是最常用的,未来最常用的还是文件式来进行编程。就是把一堆python的编程和指令写到一个.py的文件中,我们称之为python的源代码文件。可以用python解释器来重复运行程序。
注释:Ctrl+/ 复制:Ctrl+D 向下换行:Shfit+Enter 向上换行:Ctrl+Alt+Enter 移动代码:Ctrl+Shift+方向键 删除:Ctrl+Y 查找Ctrl+Shift+F 格式化(优化)代码:Ctrl+Alt+L 查看函数官方的帮助文档:Ctrl+Shift+I
注释和变量:
File→Settings(Ctrl+Alt+S)→Editor→Color Scheme→Language Defaults→Comments→Line Comment
变量名不可以随便使用,需要满足标识符的命名规则。它是Python中定义各种名字的时候的统一规范。
1.标识符
自动输入print()的小窍门。直接写要输出的代码,写好后直接在后面输入.p就会出现P相关的函数(功能),如果没出现,就再往后输入,直到看到,选择好回车。
变量的数据类型:
检测数据类型的函数:type()
输出结果为:
2.字符串
字符串其实就是一串字符,也就是说跟珠子一样串起来的字符,把它给串起来的方式。英文str。字符串输入要在单引号或者双引号内输入。
a = 'Hello'
b = 'Python'
pring(c = a + b)
'HelloPython'
print(a * 2)
'HelloHello'
print('H' in a)
True
print('H' not in a)
False
print(a[1:4])
ell
格式化输出
按照我们自己想要的输出格式,先定义一个模板,照着模版输出。
print(模版 % 变量名 )
输出结果:我的名字是Sam,年龄是18。
技巧:
按照四舍五入应该是22.35
注意:因为计算机只认识和处理进制数值,在实际的计算中,所有的数据都必须为二进制,计算后又转换回来,就是在这个过程中造成数据的截断误差。
①. Format():
相对基本格式化输出采用%的方法,format()的功能更强大,该函数把字符趾当成一个模版,通过传入的参数进行格式化,并且使用大括号{}作为特殊字符代替%,它不需要考虑数据类型。
print('{} {}' . 变量名)
3.字符串操作:
①.下标:
“下标”又叫“索引”或“角标”。也就是编号,用中括号[]表示。下标的作用就是通过下标快速找到对应的数据。(所有序列都有下标)
注意:下标从左到右顺序是从0开始的,反过来就是从-1开始。
②.切片:
“切片”是指对操作的对象截取其中一部分的操作。也就是截取字符串。字符串、列表、元组都支持切片操作。
序列对象[开始位置下标:结束位置下标:步长] 步长为1可省略。步长就是跳过几个元素的意思。
口诀:包头不包尾,目标位置+1.
4.字符中的函数:
①.字符串查询(index,find)
建议使用find(),因为如果没找到匹配的字符串,index()方法会报异常。除了能查找目标字符串,还有判断功能。
string:要进行查找操作的原始字符串。
sub:必需参数,是要查找的子字符串。start:可选参数,指定开始查找的起始索引位置,默认值为 0,表示从字符串的开头开始查找。
end:可选参数,指定查找的结束索引位置,默认值为字符串的长度,表示查找至字符串的末尾。查找范围是左闭右开区间 [start, end)。
示例:2-3-4-5输出结果:
②.字符串大小写转换操作(upper lower swapcase capitalize和title)
text = "hello, world!"
print(result) # 输出: HELLO, WORLD!
text = "HELLO, WORLD!"
print(result) # 输出: hello, world!
text = "Hello, World!"
print(result) # 输出: hELLO, wORLD!
text = "hello, world!"
print(result) # 输出: Hello, world!
text = "hello, world!"
print(result) # 输出: Hello, World!
③.字符串对齐(center just和zfill)
string:需要进行处理的原始字符串。
width:必需参数,指定期望字符串最终达到的总宽度。若该宽度小于或等于原始字符串的长度,会直接返回原始字符串。
fillchar:可选参数,用于填充的字符,此字符必须为单个字符。若不提供该参数,默认会使用空格进行填充。
输出结果:
输出结果:
输出结果:
输出结果:
④.分割字符串(split splitlines和partition)
string:需要进行分割操作的原始字符串
sep:可选参数,用于指定分割字符串的分隔符。如果不提供该参数,默认会使用任意空白字符(像空格、制表符、换行符等)作为分隔符
maxsplit:可选参数,用于指定最大分割次数。若设置为 -1(默认值),则表示不限制分割次数,会尽可能多地进行分割
string:要进行分割操作的原始字符串
keepends:可选参数,是一个布尔值
若 keepends 为 False(默认值),分割结果中不保留行边界符(如换行符 \n、回车符 \r 等)
若 keepends 为 True,分割结果中会保留行边界符
string:需要进行分割操作的原始字符串
sep:必需参数,是用于分割字符串的分隔符
⑤.合并与替换(join replace)
separator:用于连接元素的字符串。
iterable:包含多个元素的可遍历迭代对象,如列表、元组等。
old:需要被替换的旧子字符串。
new:用于替换旧子字符串的新字符串。
count:可选参数,指定替换的最大次数。如果省略该参数,则会替换所有匹配的旧子字符串。
⑥.判断字符串(isidentifier isspace isalpha is decimal isnumeric和isalnum)
string:表示要进行检查的字符串。
返回值:如果字符串是有效的 Python 标识符,则返回 True;否则返回 False。
检查字符串是否是一个有效的 Python 标识符(字符 数字 下划线)
string:要进行检查的字符串。
返回值:如果字符串中的所有字符都是字母且字符串长度至少为 1,则返回 True;否则返回 False。
string:需要进行检查的字符串。
返回值:如果字符串中的所有字符都是十进制字符,并且字符串的长度至少为 1,则返回 True;否则返回 False。
string:要进行检查的字符串。
该方法不需要传入参数,它会返回一个布尔值:如果字符串中的所有字符都是数字,则返回 True;否则返回 False。
string:要进行检查的字符串。
该方法不需要传入参数,会返回一个布尔值。如果字符串中的所有字符都是字母或数字,则返回 True;否则返回 False。
string:要进行检查的字符串。
该方法不接受任何参数,会返回一个布尔值。如果字符串中所有字母字符都是小写,且至少有一个字母字符,则返回 True;否则返回 False。
string:需要进行检查的目标字符串。
此方法不接受任何参数,它会返回一个布尔值。若字符串里所有字母字符均为大写,并且字符串中至少存在一个字母字符,那么返回 True;反之则返回 False。
该方法不接受任何参数,会返回一个布尔值。如果字符串中每个单词的首字母都是大写,其余字母都是小写,并且字符串中至少有一个字母字符,则返回 True;否则返回 False。
该方法不接受任何参数,返回一个布尔值。如果字符串中的所有字符的 Unicode 码点都在 0 - 127 之间(即 ASCII 字符集范围),则返回 True;否则返回 False。
该方法不接受任何参数,会返回一个布尔值。如果字符串中的所有字符都是可打印的,那么返回 True;反之则返回 False。
prefix:必需参数,表示要检查的前缀,可以是字符串或者元组(如果是元组,则会依次检查元组中的每个前缀)。
start:可选参数,指定开始检查的索引位置,默认值为 0,即从字符串的开头开始检查。
end:可选参数,指定结束检查的索引位置,默认值为字符串的长度,即检查到字符串末尾。
suffix:这是必需参数,可以是单个字符串,也可以是由多个字符串组成的元组。若为元组,会依次检查字符串是否以元组中的任意一个字符串结尾。
start:可选参数,代表开始检查的索引位置,默认值为 0,意味着从字符串的起始位置开始检查。
end:可选参数,代表结束检查的索引位置,默认值是字符串的长度,也就是检查到字符串的末尾。
⑦.去除两端多余字符操作
chars:可选参数,是一个字符串,指定要从字符串左侧移除的字符序列。如果不提供该参数,默认移除字符串左/右侧的空白字符(包括空格、制表符 \t、换行符 \n、回车符 \r 等)。
返回值:返回一个新的字符串,该字符串是原字符串移除左/右侧指定字符序列后的结果,原字符串不会被修改。
chars(可选):指定要去除的字符序列。如果省略该参数,则默认去除字符串首尾的空白字符(包括空格、制表符、换行符等)。
返回值:返回去除指定字符后的新字符串,原字符串不会被修改。
5.运算符
input() 输入框加提示 输出的值全都是字符串类型
输出结果:
②.赋值运算符
③.复合赋值运算符
注意:先计算后赋值
④.比较运算符
比较运算符也叫关系运算符,通常用来判断
如 a = 7,b = 3 则print(a >= b)为True
如 a = 7,b = 7 则print(a >= b)为True
如 a = 7,b = 3 则print(a <= b)为False
如 a = 7,b = 7 则print(a <= b)为True
⑤.逻辑运算符
6.转义字符
\' 或
\“
True和False的界定:任何非零(0),非空(None)的对象都为真(True)。
数字0、空对象(None)均为假(False) ,判断的返回值为True(1)和False(0)。
两种流程控制语句:①.条件语句:if让程序根据条件有选择性的执行语句。
if子句必须有,elif子句可以有0个或者多个,else子句可以有0个或1个,且只能放在if子句最后。
在 Python 中,条件&判断&循环语句结构是通过冒号(:)和缩进(Tab键或是四个空格)来制定的。不缩进,外边的代码块就跟if没有关系。
②.判断循环语句if-else if-elif-else
if语句用于根据条件来决定是否执行特定的代码块。如果条件为真True,则执行if块中的代码。
if-else是大多数编程语言中用于实现条件判断的控制结构,它允许程序根据不同的条件执行不同的代码块。
多条件判断if-elif-else在实际应用中,可能需要处理多个条件。
if嵌套是指在一个if语句的代码块中再包含另一个或多个if语句。这种结构允许你处理更复杂的条件逻辑。
①.for循环语法
for 临时变量 in 序列:
重复执行的代码1
重复执行的代码2
……………………
for循环读取
输出结果:
②.while 循环语法
while 条件:
条件成立重复执行的代码1
条件成立重复执行的代码2
………………………………
while循环读取
输出结果:
*号直角三角形
输出结果:
九九乘法表while循环
求100以内的素数(质数)
素数是只能被 1 和它本身整除的正整数。
上述代码中,外层的for循环遍历从 2 到 100 的所有数字,因为 1 不是素数,所以从 2 开始。对于每个数字num,我们假设它是素数(将is_prime设为True),然后内层的for循环从 2 到该数的平方根(使用int(num ** 0.5) + 1)检查是否存在能整除它的数。如果存在这样的数,就将is_prime设为False并跳出内层循环。最后,如果is_prime仍然为True,则说明该数是素数,将其打印出来。
range函数:用于生成一系列不可变的整数序列,常用于 for 循环中控制迭代次数。
range() 函数有三种不同的调用方式:
①. range(stop)
参数说明:stop 是一个整数,表示生成序列的结束值(不包含该值)。生成的序列从 0 开始,步长为 1。
②. range(start, stop)
参数说明:start 是一个整数,表示生成序列的起始值(包含该值);stop 是一个整数,表示生成序列的结束值(不包含该值)。生成的序列步长为 1。
③. range(start, stop, step)
参数说明:start 是起始值(包含该值),stop 是结束值(不包含该值),step 是步长,即相邻两个数之间的差值,可以是正数或负数,但不能为 0。
九九乘法表for循环
输出结果:
猜拳游戏
break和continue只能够在循环体内使用。
break(中断,强行终止):中途退出,结束循环。不再继续当层循环。只对当层循环有效。
continue(继续):结束当前的本轮循环,后面的代码不再执行,然后进行下一轮循环。
死循环
列表[list]:可以一次存储多个数据。用中括号[]包围所有元素,每个元素间用逗号隔开。
特性:有序。存储多个数据时,元素可以是不同类型。
列表[list]是可变的数据结构,可以通过索引来直接修改列表中的元素。
列表的操作:增删改查
insert() 方法会直接修改原列表,而不会返回一个新列表。
用于在列表的末尾添加一个新元素,只能添加一个元素。该元素可以是任意数据类型,比如整数、字符串、列表、元组、字典等。
将可迭代对象的每个元素添加到列表中,可一次添加多个元素。
del:用于删除对象或对象的元素。它可以用于删除变量、列表中的元素、字典中的键值对,甚至删除整个对象。
删除后该变量将不再存在。
可以移除并返回列表中指定索引位置的元素。如果不指定索引,默认移除并返回列表的最后一个元素。
列表排序
reverse=False:这是默认值,表示进行升序排序。
reverse=True:表示进行降序排序。
reverse() 是列表对象独有的方法,它的作用是将列表中的元素顺序进行反转,也就是首尾颠倒,该方法会直接修改原列表,且没有返回值(返回 None)。
sorted(iterable, key=None, reverse=False)
元组(tuple)是一种不可变的序列类型,用于存储多个元素。元组使用圆括号 () 来表示,元素之间用逗号分隔。需要注意的是,当元组中只有一个元素时,需要在元素后面加上逗号,否则会被视为普通的数据类型。
访问元组元素:同列表一样使用索引来访问元素,索引从 0 开始,也支持负数索引从末尾访问。
元组同样支持切片操作,语法和列表的切片操作一致,即 tuple[start:stop:step]。
元组的一个重要特性是不可变,这意味着一旦创建了元组,就不能修改、添加或删除其中的元素。
元组的常用方法:count() 用于返回指定元素在元组中出现的次数。
index() 用于返回指定元素在元组中第一次出现的索引,如果元素不存在则会引发 ValueError。
元组的遍历:可以使用 for 循环来遍历元组中的元素。
元组的长度:使用 len() 函数可以获取元组的长度。
元组的优点:
由于元组是不可变的,Python 在处理元组时会有一些性能上的优化,比如元组的哈希操作比列表更快,所以元组可以作为字典的键。
不可变性保证了数据在程序运行过程中不会被意外修改,提高了数据的安全性。
元组和列表的互转
可以使用 list() 函数将元组转换为列表,使用 tuple() 函数将列表转换为元组。
字典(dict):是一种无序、可变且可迭代的数据类型,用于存储键值对(key - value pairs)。每个键必须是唯一的,且键必须是不可变的数据类型(如字符串、数字或元组),而值可以是任意数据类型(如字符串、数字、列表、元组、字典等)。
创建字典:使用花括号{}
使用dict()构造函数
访问字典中的值
可以通过键来访问字典中的值,如果键不存在,会引发 KeyError 异常。
修改和添加键值对
删除键值对:可以使用 del 语句或 pop() 方法删除字典中的键值对。
字典的常用方法
keys():返回一个包含字典所有键的视图对象。
values():返回一个包含字典所有值的视图对象。
items():返回一个包含字典所有键值对的视图对象。
clear():清空字典。
copy():返回字典的浅拷贝。
遍历字典:可以使用 for 循环遍历字典的键、值或键值对。
输出结果:
集合(set):是一种无序、可变且不包含重复元素的数据类型。集合主要用于成员检测、消除重复元素以及进行交集、并集、差集等数学运算。
创建集合:使用花括号{}
使用 set() 构造函数
访问集合元素
由于集合是无序的,不能通过索引访问集合中的元素。但可以使用 in 关键字检查元素是否存在于集合中。
添加元素
add() 方法:用于向集合中添加单个元素。
update() 方法:用于向集合中添加多个元素,可以是列表、元组、集合等可迭代对象。
删除元素
remove() 方法:用于删除集合中的指定元素,如果元素不存在,会引发 KeyError 异常。
discard() 方法:用于删除集合中的指定元素,如果元素不存在,不会引发异常。
pop() 方法:随机删除并返回集合中的一个元素。
clear() 方法:清空集合中的所有元素。
集合的数学运算
交集(& 或 intersection() 方法):返回两个集合中共同拥有的元素。
并集(| 或 union() 方法):返回两个集合中所有不重复的元素。
差集(- 或 difference() 方法):返回在第一个集合中但不在第二个集合中的元素。
对称差集(^ 或 symmetric_difference() 方法):返回两个集合中不共同拥有的元素。
集合的其他常用方法
len():返回集合中元素的数量。
issubset():判断一个集合是否是另一个集合的子集。
issuperset():判断一个集合是否是另一个集合的超集。
成员运算符
in:主要用于检查某个元素是否是另一个序列(如列表、元组、字符串、集合、字典等)的成员。
not in:用于检查某个元素是否不在特定的数据结构或集合中
count: 用于统计指定元素在列表 字符串 元组等出现的次数。
推导式(Comprehension)是一种简洁且高效的创建列表、集合、字典等数据结构的方式。它允许你使用简洁的语法从一个可迭代对象(如列表、元组、集合等)中快速生成新的数据结构。
列表推导式:用于快速创建列表。 语法:[expression for item in iterable if condition]
expression:是对每个 item 进行操作的表达式,最终结果会作为新列表的元素。
item:是从 iterable 中取出的每个元素。
iterable:是一个可迭代对象,如列表、元组、集合等。
if condition:是可选的条件语句,用于过滤元素,只有满足条件的元素才会被包含在新列表中。
集合推导式:集合推导式与列表推导式类似,只不过它生成的是集合(set),集合中的元素是唯一的。
字典推导式:用于快速创建字典。
语法:{key_expression: value_expression for item in iterable if condition}
函数格式:
def 函数名(参数):
内部代码有缩进(Tab)键
函数名()
传值:直接往小括号里面写你要传递的数据。
注意:def 变量名():这个变量名可以随便起名字,最好是按照代码的功能去起名字。做到见字明意。
如果在定义的小括号里面没有写参数,也就是变量,那么就不要去传。
如果在定义的小括号里面写了参数,也就是变量,写了几个就传递几个。
return返回值
全局环境&局部环境:局部变量可以使用全局变量,反过来,则不行。
只有def定义的函数的内部代码块才算是局部环境变量,不是看缩进。
global:将局部环境变量升级为全局环境变量。
文件操作:
r:创建原始字符串(raw string)的前缀。目的是防止反斜杠 \ 被当作转义字符处理,从而准确表示文件的完整路径。
open():打开文件并返回一个文件对象,借助这个文件对象,你可以对文件进行读取、写入、追加等操作。
mode 参数:该参数用于指定文件的打开模式,常见的模式有以下几种:
'r':只读模式(默认值),用于读取文件内容。若文件不存在,会抛出 FileNotFoundError 异常。
'w':写入模式,用于向文件写入内容。如果文件已存在,会先清空文件内容;若文件不存在,则会创建新文件。
'a':追加模式,用于在文件末尾追加内容。若文件不存在,会创建新文件。
'b':二进制模式,可与上述模式组合使用(如 'rb'、'wb'),用于处理二进制文件(如图片、音频等)。
'x':创建模式,若文件不存在则创建新文件并以写入模式打开;若文件已存在,会抛出 FileExistsError 异常。
with语句:
with 语句是 Python 中的上下文管理器,用于简化资源管理。在处理文件、网络连接、数据库连接等需要手动打开和关闭的资源时,使用 with 语句可以自动完成资源的清理工作,无需手动调用 close() 方法。当代码块执行完毕或出现异常时,with 语句会自动调用资源对象的 __exit__() 方法来关闭资源。简单的说,它会自动管理文件的打开和关闭,当代码块执行完毕后,文件会被自动关闭,避免了手动调用 close 方法的麻烦
正则表达式:
在Python中正则表达式是一种强大的文本处理工具,用于匹配、查找、替换和分割字符串。Python 通过re模块提供了对正则表达式的支持。
re模块示例(匹配以itcast开头的语句)
匹配对象常用的方法:
输出结果:
常用的正则表达式元字符和模式
注册信息:
time模块
常用函数
struck_time 对象是一个元组,包含以下属性:
常见的格式代码如下:
没有使用多线程任务
多任务-线程
使用多线程任务
线程的基本概念
线程是程序执行流的最小单元,一个进程可以包含多个线程,这些线程可以并发执行,共享进程的资源(如内存、文件句柄等)。与进程相比,线程的创建和销毁开销较小,切换速度也更快。
Python的标准库threading线程模块
输出结果:
带参数的线程任务
查看线程数量
线程同步问题
由于多个线程可以共享进程的资源,当多个线程同时访问和修改共享资源时,可能会出现数据不一致的问题,即线程安全问题。为了解决这个问题,可以使用锁机制。
线程的优点
提高程序的执行效率:多个线程可以并发执行,充分利用多核处理器的资源,加快程序的执行速度。
线程的缺点
线程安全问题:多个线程同时访问和修改共享资源时,可能会出现数据不一致的问题,需要使用锁等同步机制来解决。
上下文切换开销:线程的切换需要保存和恢复上下文信息,会带来一定的开销。
调试困难:多线程程序的执行顺序是不确定的,调试时可能会出现难以复现的问题。
多进程任务multiprocessing模块
if __name__ == '__main__':语句是为了避免在 Windows 等系统下出现递归创建进程的问题,因为 Windows 系统在创建新进程时会重新导入主模块,所以需要使用该语句来确保代码只在主进程中执行。
isinstance() 语法:isinstance(object,classinfo)
用于判断一个对象是否是某个类的实例,或者是否是某些类中的一个类的实例。
参数解释:object:需要进行类型检查的对象。classinfo:可以是单个类、类型,或者由多个类、类型组成的元组。
返回值:如果 object 是 classinfo 类型的实例,或者是 classinfo 元组中任意一个类型的实例,则返回 True;否则返回 False。
①.检查对象是否是单个类的实例
②.检查对象是否是多类中的一个类的实例
③.与内置类型一起使用
pass 是一个空语句,它不执行任何操作,主要用于语法上需要语句但又不需要实际执行任何代码的场景
①.在函数中定义中使用
当你想要先定义一个函数,但还没有想好具体的实现逻辑时,可以使用 pass 占位。这样可以保证函数定义的语法正确性,后续再补充具体的函数体内容。
②.在类定义中使用
和函数定义类似,当你想要先定义一个类,但还未确定类的具体属性和方法时,可以使用 pass 占位。
③.在条件语句中使用
在条件语句(如 if、elif、else)中,有时可能某个条件分支暂时不需要执行任何操作,此时可以使用 pass 占位。
④.在循环语句中使用
在循环语句(如 for、while)中,有时可能某个循环体暂时不需要执行任何操作,同样可以使用 pass 占位。
迭代器(Iterator)是一个实现了迭代器协议的对象,它可以用于遍历可迭代对象(如列表、元组、字典等)中的元素。迭代器协议要求对象实现两个方法:__iter__() 和 __next__()。
可迭代对象(interable):是指可以返回一个迭代器的对象,常见的可迭代对象有列表、元组、字符串、字典等。可以使用 iter() 函数将可迭代对象转换为迭代器。
①.迭代器(Iterator)是一个实现了 __iter__() 和 __next__() 方法的对象。__iter__() 方法返回迭代器本身,__next__() 方法返回迭代器的下一个元素,当没有更多元素时,抛出 StopIteration 异常。
iter() 函数:用于将可迭代对象转换为迭代器。
next() 函数:用于获取迭代器的下一个元素。
②.使用for循遍历迭代器
for 循环在内部会自动调用 iter() 函数将可迭代对象转换为迭代器,并使用 next() 函数逐个获取元素,直到抛出 StopIteration 异常。
③.自定义迭代器
你可以通过定义一个类并实现 __iter__() 和 __next__() 方法来创建自定义迭代器。
StopIteration 异常:通常在迭代器中使用,用于表示迭代结束。当迭代器没有更多元素可供迭代时,会抛出该异常。
迭代器是惰性的,它只在需要时才计算和返回下一个元素,这可以节省内存和计算资源。迭代器只能向前遍历元素,不能后退或重置,一旦迭代结束,就不能再次使用该迭代器进行遍历,需要重新创建迭代器。
IndexError 异常:通常在你尝试访问序列(如列表、元组、字符串等)中不存在的索引时抛出。
TypeError 异常:表示操作或函数应用于不兼容类型的对象时引发的错误。
raise 关键字:用于主动抛出异常,你可以抛出内置的异常类型,也可以自定义异常类型。
抛出内置ZeroDivisionError异常
自定义异常并抛出
生成器(Generator):是一种特殊的迭代器,它允许你在需要时逐个生成值,而不是一次性生成所有值。这种特性使得生成器在处理大量数据时非常高效,因为它不需要一次性将所有数据加载到内存中。
生成器函数:是一种特殊的函数,使用 yield 关键字来定义。当调用生成器函数时,它并不会立即执行函数体中的代码,而是返回一个生成器对象。每次调用生成器对象的 __next__() 方法(或者使用 next() 内置函数)时,函数会执行到下一个 yield 语句,返回 yield 后面的值,并暂停执行。
生成器表达式:是一种简洁的创建生成器的方式,它类似于列表推导式,但使用圆括号而不是方括号。生成器表达式返回一个生成器对象,而不是一个列表。
输出结果:
生成器的优势
①.节省内存:生成器逐个生成值,不需要一次性将所有值存储在内存中,因此在处理大数据集时非常高效。
②.延迟计算:生成器只有在需要时才会生成值,避免了不必要的计算。
生成器的常见使用场景
处理大数据集:例如读取大文件时,可以使用生成器逐行读取文件内容,而不是一次性将整个文件加载到内存中。
无限序列生成
生成器可以用于生成无限序列,例如斐波那契数列。
协程(Coroutine):是一种比线程更加轻量级的并发编程方式。它允许在程序执行过程中暂停和恢复,从而实现高效的异步操作。
基于生成器的协程(Python早期协程实现)
在 Python 2.5 及以后的版本中,可以使用生成器和 yield 关键字来实现简单的协程。
基于asyncio库的协程(Python3.4以后)
asyncio 是 Python 标准库中用于编写异步 I/O 代码的库,它提供了更高级的协程支持。
async def:用于定义异步函数,异步函数也称为协程函数。
await:用于暂停协程的执行,等待一个可等待对象(如另一个协程、Future 或 Task)完成。
并发执行多个协程
UDP(User Datagram Protocol)即用户数据报协议,是一种无连接的传输层协议,与 TCP(传输控制协议)同为互联网传输层的两大主流协议。
无连接:在进行数据传输之前,不需要像 TCP 那样先建立连接。发送方可以随时向接收方发送数据报,接收方只要处于监听状态就可以接收数据。
不可靠:UDP 不保证数据一定能到达目的地,也不保证数据的顺序和完整性。如果数据在传输过程中丢失、重复或乱序,UDP 本身不会进行重传、排序等操作。
高效性:由于不需要建立连接和维护复杂的状态信息,UDP 的开销较小,传输速度快,实时性好。因此,UDP 适用于对实时性要求较高、对少量数据丢失不太敏感的应用场景,如音频和视频流、实时游戏等。
在 Python 中,可以使用 socket 模块来实现 UDP 通信。
UDP服务器端代码:
代码解释:
使用 bind() 方法将套接字绑定到指定的 IP 地址和端口号。
使用 recvfrom() 方法接收客户端发送的数据和客户端地址,1024 表示一次最多接收 1024 字节的数据。
使用 sendto() 方法向客户端发送响应消息。
UDP客户端代码:
代码解释:
使用 sendto() 方法将消息发送到服务器。
使用 recvfrom() 方法接收服务器的响应。
使用 close() 方法关闭套接字。
注意事项:
UDP 数据报有最大长度限制,一般为 65507 字节(包括 UDP 头部 8 字节),实际应用中需要考虑数据大小,避免数据丢失。
由于 UDP 是不可靠的协议,在实际应用中需要考虑数据丢失、重复等问题,并进行相应的错误处理。
TCP(Transmission Control Protocol)即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
在进行数据传输之前,需要先建立连接,传输完成后再断开连接。这种连接机制确保了通信双方可以可靠地进行数据交互,称为面向连接。
TCP 通过一系列机制来保证数据的可靠传输,包括确认应答、重传机制、滑动窗口协议、拥塞控制等。如果数据在传输过程中丢失、损坏或乱序,TCP 会自动进行重传和排序,确保接收方能够正确接收到完整的数据。
TCP 将应用层的数据看作是无结构的字节流进行传输,它会将数据分割成合适大小的数据包进行发送,并在接收端将这些数据包重新组装成完整的字节流。
在 Python 中,可以使用 socket 模块来实现 TCP 通信。
TCP服务器端代码:
代码解释:
使用 bind() 方法将套接字绑定到指定的 IP 地址和端口号。
使用 listen() 方法开始监听客户端的连接请求,参数表示允许的最大连接数。
使用 accept() 方法等待客户端的连接,该方法会返回一个新的套接字对象和客户端的地址。
使用 recv() 方法接收客户端发送的数据,使用 sendall() 方法向客户端发送响应消息。
使用 close() 方法关闭客户端连接。
TCP客户端代码:
代码解释:
使用 connect() 方法连接到指定的服务器地址和端口。
使用 sendall() 方法向服务器发送消息,使用 recv() 方法接收服务器的响应。
使用 close() 方法关闭套接字。
注意事项:
在使用 TCP 时,需要注意连接的建立和关闭,避免出现连接泄漏的问题。
由于 TCP 是字节流协议,在处理数据时需要注意数据的边界问题,避免出现粘包和半包的情况。可以通过自定义协议、使用固定长度的数据块或添加分隔符等方式来解决。
在网络通信中,可能会出现各种异常情况,如连接超时、网络中断等,需要在代码中进行适当的异常处理,以增强程序的健壮性。
闭包(Closure):是一个非常重要的概念,它结合了函数和其相关的引用环境,让函数能够记住并访问其定义时的外部(非全局)变量。
闭包的定义:是指有权访问另一个函数作用域中变量的函数,即使该函数已经执行完毕,其作用域内的变量也不会被销毁,而是会被闭包所引用。
闭包的形成条件:①.存在嵌套函数:在一个函数内部定义另一个函数。
②.内部函数引用外部函数的变量:内部函数使用了外部函数中定义的变量。
③.外部函数返回内部函数:外部函数将内部函数作为返回值返回。
代码解释:
outer_function 是外部函数,接受一个参数 x。
inner_function 是内部函数,接受一个参数 y,并引用了外部函数的变量 x。
outer_function 返回了 inner_function,形成了闭包。
调用 outer_function(10) 返回一个闭包 closure,此时 x 的值被固定为 10。
调用 closure(5) 相当于调用 inner_function(5),计算 x + y 的值,即 10 + 5 = 15。
闭包的应用场景
①.数据封装和隐藏:闭包可以将数据封装在函数内部,只提供必要的接口进行访问,从而实现数据的隐藏和保护。
在这个例子中,count 变量被封装在 counter 函数内部,外部无法直接访问,只能通过调用 increment 函数来修改和获取 count 的值。
在 Python 里,函数内部可以定义另一个函数,形成嵌套函数结构。内部函数默认情况下只能访问外部函数的变量,但不能直接对其进行修改。如果尝试在内部函数中直接对外部函数的变量进行赋值操作,Python 会认为你是在内部函数作用域中创建了一个新的局部变量,而不是修改外部函数的变量。
nonlocal 关键字的作用就是告诉 Python 解释器,在内部函数中使用这个关键字声明的变量,它不是内部函数的局部变量,而是外部(非全局)函数作用域中的变量,这样就可以在内部函数中修改该变量的值。
代码解释:
outer_function 函数:这是外部函数,它定义了一个局部变量 count 并初始化为 0,然后定义了一个内部函数 inner_function,最后返回 inner_function。
inner_function 函数:这是内部函数,在函数内部使用 nonlocal count 声明 count 变量是外部函数的变量,然后对 count 进行加 1 操作并返回。
创建闭包并调用:调用 outer_function() 返回一个闭包 closure,每次调用 closure() 时,内部函数 inner_function 会修改外部函数的 count 变量的值,并返回更新后的 count 值。
对比不使用 nonlocal 的情况
在这个例子中,由于没有使用 nonlocal 关键字,inner 函数内部的 num = 20 会创建一个新的局部变量 num,而不会影响外部函数的 num 变量。
②.实现装饰器:装饰器是闭包的一个常见应用,它可以在不修改原函数代码的情况下,为函数添加额外的功能。
在这个例子中,log_decorator 是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数 wrapper。wrapper 函数在调用原函数前后添加了日志输出功能。
闭包的优缺点
优点:数据封装和隐藏:可以将数据封装在函数内部,避免全局变量的使用,提高代码的安全性和可维护性。
代码复用:闭包可以将一些通用的逻辑封装在内部函数中,提高代码的复用性。
缺点:内存占用:由于闭包会引用外部函数的变量,这些变量不会被垃圾回收机制回收,可能会导致内存占用过高。
性能问题:闭包的调用会涉及到多层函数调用,可能会对性能产生一定的影响。
装饰器(Decorator)是一种强大且实用的语法糖,它允许你在不修改原有函数代码的基础上,对函数的功能进行扩展。
装饰器的定义和原理
装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。新的函数通常会在原函数的基础上添加一些额外的功能,如日志记录、性能测试、权限验证等。装饰器的实现基于闭包的概念,利用闭包可以访问外部函数作用域中变量的特性,将原函数封装在新的函数内部。
代码解释:
log_decorator 函数:这是一个装饰器函数,它接受一个函数 func 作为参数,并返回一个新的函数 wrapper。
wrapper 函数:这是一个闭包函数,它在调用原函数 func 前后添加了日志输出功能。
装饰过程:通过 hello = log_decorator(hello) 将 hello 函数传递给 log_decorator 函数进行装饰,返回一个新的函数并重新赋值给 hello。
调用被装饰后的函数:调用 hello() 实际上是调用 wrapper() 函数,从而实现了在原函数基础上添加日志功能的目的。
语法糖写法
Python 提供了一种更简洁的语法糖来使用装饰器,使用 @ 符号直接在函数定义上方指定装饰器。
输出结果:
如果原函数需要接受参数,那么装饰器的 wrapper 函数也需要接受相应的参数,并将这些参数传递给原函数。
在这个例子中,wrapper 函数使用 *args 和 **kwargs 来接受任意数量的位置参数和关键字参数,并将它们传递给原函数 add。
输出结果:
装饰器本身也可以接受参数,这需要在装饰器函数外面再嵌套一层函数。
代码解释
repeat 函数:这是一个接受参数的装饰器工厂函数,它接受一个整数 n 作为参数,并返回一个装饰器函数 decorator。
decorator 函数:这是一个普通的装饰器函数,它接受一个函数 func 作为参数,并返回一个新的函数 wrapper。
wrapper 函数:在 wrapper 函数内部,使用 for 循环调用原函数 n 次。
装饰器的应用场景
权限验证:在调用函数前验证用户的权限,只有具备相应权限的用户才能调用该函数。