python
1.基本使用
-
输入输出
-
print()打印到屏幕
-
-
input()
-
raw_input()
-
-
-
进入和退出python命令窗口中
-
进入:python
-
退出函数:exit()
-
-
执行python文件
-
想要执行命令的话想要找到文件然后用(python)文件和后缀名
-
如:a.py
-
-
同一行显示多条语句
-
Python可以在同一行中使用多条语句,语句之间使用分号(;)分割,以下是一个简单的实例。
-
import sys; x = ‘runoob’; sys.stdout.write(x + ‘\n’)
-
-
帮助信息
-
很多程序可以执行一些操作来查看一些基本信息,Python可以使用-h参数查看各参数帮助信息:
-
$ python -h
-
我们在使用脚本形式执行 Python 时,可以接收命令行输入的参数,具体使用可以参照 Python 3 命令行参数。
-
python的第一行命令 //# –– coding:utf-8 –– 设置为utf-8
-
-
-
函数
-
challable()判断对象是否可以被调用,能被调用的对象就是一个callables对象,比如函数
-
ascii()调用对象的repr()方法,获得该方法的返回值.ascii() ,函数会将所有非 ascii 字符替换为转义字符:
-
dir()不带参数时返回当前范围内的变量,方法和定义的类型列表,带参数时返回参数的属性,方法列表。
-
classmethod()用来指定一个方法为类的方法,由类直接调用执行,只有一个cls参数,执行类的方法时,自动将调用该方法的类赋值给cls.没有此参数指定的类的方法为实例方法。
-
delattr()删除对象的属性
-
filter() 过滤器,构造一个序列,等价于[ item for item in iterables if function(item)],在函数中设定过滤条件,逐一循环迭代器中的元素,将返回值为True时的元素留下,形成一个filter类型数据。
filter(function, iterable) 参数function:返回值为True或False的函数,可以为None。 参数iterable:序列或可迭代对象。 def uno(x): return x > 10 v=filter(uno,[1,11,2,45,7,6,13])
-
iter()
# 参数二必须是一个可迭代对象,每次调用iterator的next()方法来无 # 参数的调用o,如果返回值等于参数sentinel,触发StopIteration异常,否则将返回该值。 def a(a): pass iter(a,[1,2,3,4,])
-
三元运算(三目运算)
v = 成立 if 条件 else 不成立
-
函数的模块导入
#python的第一行是 #!/usr/bin/env python # -*- coding:utf-8 -*- input() #输入函数 print() #输出函数 type() #查看数据类型 while() #循环 pass #不做任何操作 break #终止循环 continue #回到循环位置 #编译器:是一步完成在做下一步,如c/c++/c#/java/go。 #解释器:是一行完成在做下一行,如python/php/ruby。
-
深浅拷贝
import copy # ying puo 进口 v = copy.copy(n) # kao bei拷贝浅只拷贝可变的 v = copy.deepcopy(n) # di puo kao bei深拷贝只有在嵌套的时候有用
-
2.运算符呀
-
关系运算符,指定表达式之间的关系,有6种运算关系。
作用 示例 结果 < 小于 6<5 false > 大于 6>5 true <= 小于等于 6<=5 false >= 大于等于 6>=5 false != 不等于 6!=5 true == 恒等于 6==5 false -
优先级:同级从左往右。
-
-
算数运算符,对数值型数据进行计算,有5种。
符号 作用 示例 结果 + 加法 6+5 11 – 减法 6-5 1 * 乘法 6*5 30 / 实数除法 6/5 1.2 // 整数除法 6//5 1 % 求余 6%5 1 ** 乘方 6**5 7776 -
优先级:乘方、乘除、求余、加减
-
-
逻辑运算符,判断真假,有3种。
符号 作用 示例 结果 and 与关系 2>5 and 5>4 true or 或关系 2>5 or 5>4 true not 非关系 2>5 and not 5>4 false -
优先级:或、与、非
-
-
赋值运算符,有6种
符号 作用 示例 结果 = 等于 a = 5 5 += 加等于 a +=2 7 -= 减等于 a -= 2 3 *= 乘等于 a *=2 10 /= 除等于 a /=2 2.5 %= 求余等于 a %= 2 1 -
位运算符,按二进制位来计算的,4种
符号 作用 示例 结果 说明 & 位与运算 12 & 9 8 按位全一出一 | 位或运算 12 | 9 13 按位见一出一 ^ 位异运算 12 ^ 9 5 按位异出一 ~ 反数加 ~ 12 -13 正负数调转加位,最后一位加1 << 尾加零 3<< 2 12 前面数转二进制后面数尾部加几个零 >> 头加零 3>>2 0 前面数转二进制后面数头部加几个零 -
成员运算符,属于和不属于,两种
符号 作用 示例 结果 说明 in 属于 “1” in “1234” true 1属于1234 not in 不属于 “1” not in “1234” false 1不属于1234 -
身份运算符,身份运算符用于比较两个对象的存储单元
符号 作用 示例 结果 is 有相同标识 “a” is “a” true is not 没有相同标识 “a” is not “a” true -
Python运算符优先级,以下表格列出了从最高到最低优先级的所有运算符:
运算符 描述 ** 指数 (最高优先级) ~ + – 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) * / % // 乘,除,取模和取整除 + – 加法减法 >> << 右移,左移运算符 & 位 ‘AND’ ^ | 位运算符 <= < > >= 比较运算符 <> == != 等于运算符 = %= /= //= -= += *= **= 赋值运算符 is is not 身份运算符 in not in 成员运算符 not and or 逻辑运算符
3.基本认识
3.1 编码
-
ascii:不包含中文,早期用于计算机。八位表示字节。
-
unicode :又称万国码,万国码32位表示一个字母(包含全球所有的语言)
-
utf-8:万国码的压缩,虽说32表示一个但不一定都占用,可以用过utf8来去除没用的位。
3.2 变量
-
随时变化的量被称为变量。
-
定义变量:a=1 代表a等于1
-
变量只能有数字、下划线、字母组成,不能用数字开头,不建议用下划线定义变量。一个变量可以赋给多个变量。
-
id(变量):用来查看某个变量,在内存中的地址。
3.3 保注
-
保留字即关键字,我们不能把它们用作任何标识符名称。Python 的标准库提供了一个 keyword 模块,可以输出当前版本的所有关键字:
import keyword print(keyword.kwlist) #单行注释,开头写 ''' 多行注释,开头结尾都写 '''
3.4 缩行
-
空行
-
函数之间或类的方法之间用空行分隔,表示一段新的代码的开始。类和函数入口之间也用一行空行分隔,以突出函数入口的开始。
-
空行与代码缩进不同,空行并不是Python语法的一部分。书写时不插入空行,Python解释器运行也不会出错。但是空行的作用在于分隔两段不同功能或含义的代码,便于日后代码的维护或重构。
-
记住:空行也是程序代码的一部分。
-
-
python最具特色的就是使用缩进来表示代码块,不需要使用大括号 {} 。
-
缩进的空格数是可变的,但是同一个代码块的语句必须包含相同的缩进空格数。
-
实例如下:
#单行语句 if True: print ("True") else: print ("False") #多行语句 #Python 通常是一行写完一条语句,但如果语句很长,我们可以使用反斜杠(\)来实现多行语句。 total = item_one + \ item_two + \ item_three
-
多个语句构成代码组
-
缩进相同的一组语句构成一个代码块,我们称之代码组。
-
像if、while、def和class这样的复合语句,首行以关键字开始,以冒号( : )结束,该行之后的一行或多行代码构成代码组。
-
我们将首行及后面的代码组称为一个子句(clause)。
-
print 默认输出是换行的,如果要实现不换行需要在变量末尾加上 end=””:
-
print( x, end=” ” )
-
-
4.数据类型
-
python数据类型:数字,字符串,列表,元组,字典
-
查看类型的命令:type()
-
hasattr(),hasattr(object,name)判断对象object是否包含名为name的特性(hasattr是通过调用getattr(object,name))是否抛出异常来实现的。
-
hash()哈希值hash(object)注意:可哈希的即不可变数据类型,不可哈希即可变数据类型
-
如果对象object为哈希表类型,返回对象object的哈希值。哈希值为整数,在字典查找中,哈希值用于快递比价字典的键。
-
两个数值如果相等,则哈希值也相等。
-
help()返回对象的帮助文档,调用内建的帮助系统,如果不包含参数,交互式帮助系统将在控制台启动。如果参数为字串,则可以是模块,类,方法等名称,并且帮助页面将会在控制台打印。参数也可以 。
-
object(),获取一个新的,无特性(geatureless)对象。Object是所有类的基类。它提供的方法将在所有的类型实例中共享。
-
强制转化:dict(),list(),tuple(),int(),str(),bool(),set()
4.1 数值型(Number)
-
数字类型:整型,布尔,浮点型,复数型
-
将可转为数值的函数:int(),整型:整数表示的范围是2的32次方,正负各占一半。
-
bool (布尔), 如 True;loat (浮点数), 如 1.23、3E-2;complex (复数), 如 1 + 2j、 1.1 + 2.2j
-
函数
v1 = abs(1) # 绝对值 v2 = float(55) # 转换为浮点型(小数) v3 = max([1,2,3,4,5]) # 找到最大的值 v4 = min([1,2,3,4,5]) # 找到最小的值 v5 = sum([1,2,3,4,5]) # 求和 v6 = divmod(1233,4) # 两数相除的商和余数 v7 = bool(1) # 测试对象是真值还是假值,0是假值,其他都是真值 # 进制转换 v8 =bin(15) # 将十进制整数转换为二进制,0b代表二进制 v9 = oct(8) # 将十进制整数转换为八进制,0o代表八进制 v10 = hex(8) # 将十进制整数转换为十六进制,0x代表十六进制 v11 = int("0b1101",base=2) # 将其他进制转换为十进制 参数1是需要转的字符串前面加进制代表,参数2是要转为几进制 v12 = pow(2,3) # 几得几次方 v13 = round(1.127,2) # 四舍五入,参数2是保留几位小数 v14 = chr(65) # 将十进制数字转换成Unicode编码中的对应字符串。 v15 = ord('A') # 根据字符在Unicode编码中找到其对应的十进制。 import random v16 = random.randint(65,90) # 模块调用randint生成随机数字
-
map,循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新的列表中,并返回。
-
对于参数iterable中的每个元素都应用fuction函数,并将结果作为列表返回。
-
如果有多个iterable参数,那么fuction函数必须接收多个参数,这些iterable中相同索引处的元素将并行的作为function函数的参数。
-
如果一个iterable中元素的个数比其他少,那么将用None来扩展改iterable使元素个数一致。
-
如果有多个iterable且function为None,map()将返回由元组组成的列表,每个元组包含所有iterable中对应索引处值。
-
第一个参数:必须是一个函数
-
第二个参数:(可以被for循环)
map 随机法 v1[11,22,33,44] def func(arg): return arg + 100 result = map(func,v1)#然后将函数的返回值添加到[None,None] print(list(result)) result = map (lambda x:x+100,v1) print(result) print(list(result)) filter 挑刺法 result = filter(lambda x: True if type(x)== int else False,v1) print(list(result)) result = filter(lambda x: type(x) ==int ,v1) print(list(result)) reduce 先加法 import functools v1 = ["wo","hao","e"] def func(x+y): return x+y result = functools.reduce(func,v1) print(result) import functools v1 = ["wo","hao","e"] result = functools.reduce(lambda x,y:x+y,v1) print(result)
-
4.2 字符串(String)
-
python中单引号和双引号使用完全相同。
-
使用三引号(”’或”””)可以指定一个多行字符串。
-
转义符 \反斜杠可以用来转义
-
在字符串前面添加一个 r,表示原始字符串,不会发生转义。这里的 r 指 raw,即 raw string。
-
使用\n代表换行,使用反斜杠()+n转义特殊字符。
-
使用\t代表制表符,用于空4格
-
使用\‘和\“代表可以在字符串中加入双引号和单引号。
-
-
按字面意义级联字符串,如”this ” “is ” “string”会被自动转换为this is string。
-
字符串可以用 + 运算符连接在一起,用 * 运算符重复。
-
Python 中的字符串有两种索引方式,从左往右以 0 开始,从右往左以 -1 开始。
-
Python中的字符串不能改变。
-
Python 没有单独的字符类型,一个字符就是长度为 1 的字符串。
-
字符串的截取的语法格式如下:变量[头下标:尾下标:步长]
print(str[0:-1]) # 输出第一个到倒数第二个的所有字符 print(str[0]) # 输出字符串第一个字符 print(str[2:5]) # 输出从第三个开始到第五个的字符 print(str[2:]) # 输出从第三个开始后的所有字符 print(str * 2) # 输出字符串两次 print(str + 'haaa') # 连接字符串
-
字符串方法中方法前面加is会有不同的返回结果.
-
函数
v1 = "aaaa".upper() # 变大写 v2 = "AAAA".lower() # 变小写 v3 = "aaaa".isupper() # 判断是否是大写 v4 = "AAAA".islower() # 判断是否是小写 v5 = "aaabaa".find("b") # 找到在字符串中对应值的索引位置,找不到返回-1 v6 = "123".isdigit() # 是数字为True,不是数字False v7 = "123".isdecimal() # 判断是不是数字 v8 = " dsfz".lstrip() # 去掉左边的空格 v9 = "dsfz ".rstrip() # 去掉右边的空格 v10 = " dsfz ".strip() # 去除两边空格 v11 = "nxs".replace("x","u",1) # 替换 v12 = "nsdxs".split(",",1) # 分割 v13 = "nsdxs".rsplit(",",1) # 右分割 v14 = len("nsdxs") # 计算长度 v15 = "dfghfh"[1:3:1] # 索引,三个数第一个是开头数,第二个是结尾数,第三个是跳着取。 v16 = zip([4,5,6],[1,2,3]) # 将对象逐一配对[(1, 4), (2, 5), (3, 6)] v17 = zip(*zip([4,5,6],[1,2,3])) # 与 zip 相反,*zip([4,5,6],[1,2,3]) 可理解为解压,返回二维矩阵式[(1, 2, 3), (4, 5, 6)] stri = "this is string example....wow!!!"; v18 = stri.startswith( 'is', 2, 4 ) # 只加第一个参数代表是否已什么开头,加了后代表第几个索引开始到第一个索引结束,的范围内寻找. v19 = stri.endswith( 'is', 2, 4 ) # 只加第一个参数代表是否已什么结尾,加了后代表第几个索引开始到第一个索引结束,的范围内寻找. v20 = "{0},{1}",format("li",1) # 占位符 v21 = "%s,str,%d,int" %("asd",4) # 占位符 v22 = "asd".encode("utf-8") # 用于编码,把unicode转成utf-8存储在硬盘中,默认不加参数,是把str数据转换成bytes类型 v23 = "asd".decode("utf-8") # 用于解码,默认不加参数,是把bytes数据转换成str类型 v24 = ".".join(["a","3","3"]) # 循环每个元素;并在元素和元素之间加入连接符。 v25 = "123".rjust(1, '0') # 字符串右边补零 v26 = "123".ljust(1, '0') # 字符串左边补零 v27 = "123".center(1, '0') # 字符串左右补零 v28 = range(1,100,2) # 生成数,第三个参数如果数1的话是从左到右,-1是从右到左。 v29 = "adfg".replace("a","b") # 第一个参数是要替换的字符,第二个替换成的字符,替换的个数。 v30 = "hello word".title() # 将首字母变成大写 v31 = "dfghnk".index("n") # 判断字符在字符串中的位置(注意如果指定的字符串中找不到会报错) v32 = bytes([1,2,3]) # 将一个字符串转换成字节类型4 v33 = compile("1+2",'<string>', 'eval') # 将字符串编译成python能识别或可以执行的代码,也可以将文字读成字符串再编译。 """ compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) 将source编译为代码或者AST对象。代码对象能过通过exec语句来执行或者eval()进行求值。 参数source:字符串或者AST(abstract syntax trees)对象。 参数filename:代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。 参数model:指定编译代码的种类。可以指定'exec', 'eval', 'single'。 参数flag和dont_inherit:这两个参数为可选参数。 参数model,用于标识必须当做那类代表来编译;如果是一个代码语句序列组成,则指定exec,如果是单个表达式,则指定eval;如果是一个单独的交互式语句,则指定single。必须要制定,不然肯定会报错。 """ s = ["a","b","c"] for i ,v in enumerate(s,1): # 返回一个可以枚举的对象,该对象的next()方法将返回一个元组。 print(i,v) # >>>>>1 a 2 b 3 c v34 = complex("1") # 当做字符串处理,创建一个值为real + imag * j的复数或者转化一个字符串或数为复数。如果第一个参数是字符串,则不需要指定第二个参数 v34 = exec("12+10") # 执行字符串或complie方法编译过的字符串,没有返回值 v35 = eval("1+2") #将字符串str当成有效的表达式来求值并返回计算结果,取出字符串中内容 # pyperclip模块的复制粘贴 # pip install pyperclip import pyperclip as py py.copy("Hello world!") #复制到剪切板 print(py.paste()) #如果剪切板有变化就输出 TODO 用于提示
4.3 列表型(List)
-
存储有序\重复的任意类型
-
函数
data = [1,111,1111] data.append(11111) # 追加 data.insert(1,12) # 指定位置插入元素 data.remove(12) # 值删除 v = data.pop(1) # 索引删除并返回删除的值 data.clear() # 删除全部 del data[1] # 删除索引的值 data[1]="aa" # 修改索引的值 data.extend(["a",22]) # 将一个列表里面的值放到另外一个列表中 data.sort(reverse=True) # 将数据按升序或降序排列,True是下降,Fale是上升 data.reversed() # 列表翻转 sorted(data) # 对列表进行临时排序,并不改变列表元素的顺序 enumerate(data) # 可以得到列表值、以及值的序号。 [1,2,3,4,5,6,7][slice(2,5,2)] # 切片功能 locals() # 打印当前可用的局部变量的字典
4.4 元组型(Tuple)
-
元组tuple,使用圆括号表示,与列表类似,唯一的区别是它的元素不能被修改。
4.5 字典型(Dict)
-
字典类型包括键和值,并且使用大括号表示,键值对的添加顺序没有关系,存储的键值对的关联关系。
-
函数
data = {"k1":"v1"} data.keys() # 获取所有键 data.values() # 获取所有值 data.items() # 获取所有键和值 data.get("k1",13) # 判断特定的值是否在字典中,不在默认返回None data.update() # 更新 del data["k1"] # 使用del命令来进行删除字典中的键值对,被删除的键值对永远的消失了。 data.sorted(reverse=True) # 降序排列,括号中加上reverse=True,将会变成升序。 data.setdefault("k1", "123") # 有两个参数主要用于判断键是否在某个字典中。
4.6 集合型(Set)
-
集合是无序和无重复的
-
函数
frozenset() # 创建一个不可修改的集合。 set() # 一样 # set和frozenset最本质的区别是前者是可变的,后者是不可变的。当集合对象会被改变时(例如删除,添加元素),只能使用set, # 一般来说使用fronzet的地方都可以使用set。 # 参数iterable:可迭代对象。 data = set(1,2,3,4,5,6,7) data.add(8) # 添加 data.discard(1) # 删除 data.intersection({1,"李少妻","小黑"})#(交集)v1和v2里面都有的 data.union({1,"李少妻","小黑"}) #(并集)v1和v2里面全部的 data.difference({1,"李少妻","小黑"}) #(差集)v1里面没有的 data.symmetric_difference({1,"李少妻","小黑"})# (对称差集)
-
集合(嵌套):列表\字典\集合都是可变的不能嵌套
4.7 布尔型(Bool)
-
True、False
4.8 数组
-
函数
import scipy.io as sio a = np.ones((2, 3, 4, 5)) # 以下都省略 import numpy as np a.shape # 查看数组维数的大小。 b = np.transpose(a,(3, 2, 1, 0)) # 改变数组维数的位置,如把3*5的矩阵变成5*3,每个数字表示a数组所在的维数位置,如3表示把a中最后一维换到b的第一维 c = sio.loadmat('x_data_6_for_mxnet.mat') # 加载.mat文件(matlab数据格式),特别适合高维的.mat文件。 dict = {'a' : 'apple', 'b' : 'banana', 'g' : 'grape', 'o' : 'orange'} a_value = dict['a'] # 取dict中的一个value。 a_value a.size # 查看数组的元素个数。 from mxnet import nd x = nd.array([3.0]) x.asscalar() # 转换ndarray数据(mxnet中的数据)为python数据。 seasons = ['Spring', 'Summer', 'Fall', 'Winter'] list(enumerate(seasons)) # 用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
5.文件操作
-
open,打开、close,关、read,读、write,写、seek,调整光标的位置、readlines,每一行分割
-
只读只写字符串(r、w、a)、可读可写字符串(r+、w+、a+)、只读只写二进制(rb、wb、ab)、可读可写二进制(r+b、w+b、a+b)
f = open('美女模特空姐护士联系方式.txt',mode='r',encoding='utf-8') content = f.read() print(content) f.close() f = open('美女模特空姐护士联系方式.txt',mode='w',encoding='utf-8') content = f.write(b"nihao") #是以二进制储存 print(content) f.close() f = open("a.txt",mode="wb") data = "我好空" content = data.encode("utf-8") f.write(content) f.close
-
tell,获取当前光标所在的字节位置、flush,强制把内存里面的东西刷到硬盘上
-
简便方式
#青年方式 # replace 替换 with open("a.txt",mode="r",encoding = "utf-8") as f1: data = f1.read() new_data = data.replace("飞沙","666") print(new_data)
-
保存变量
# shelve保存变量 import shelve shelfFile = shelve.open("mydata") shelfFile["cats"] = ["alex","wupeiqi"] #加一次使用时直接打开索引即可,cats就是键。 shelfFile["cats"] shelfFile.close() # pprint.pformat保存变量 import pprint cats = [{"name":"alex","desc":"chubby"}] pprint.pformat(cats) fileObj = open("myCats.py","w") fileObj.write("cats = "+pprint.pformat(cats)+"\n") fileObj.close() import myCats myCats.cats myCats.cats[0]
-
大文件可以用这种方法
f1 = open("a.txt",mode="r",encoding="utf-8") f2 = open("b.txt",mode="w",encoding="utf-8") for i in f1: n = i.replace("nihao","nisi") f2.write(n) f1.close() f2.close()
-
三元运算(三目运算)
# v = 成立 if 条件 else 不成立 data = input(">>>") value = ing(data) if data.isdecimal() else None
6.用函数呀
-
截至目前:面向过程编程。【可读性差/可重复性差】。
-
写代码的方式:面向过程–>函数式编程–>面向对象编程
-
本质:将n行代码拿到别处并给起个名字,以后通过名字就可以找到这段代码被执行。
-
场景:代码重复执行,代码量特别多超过一屏,可以选择通过函数进行代码的分割。
def send_email(): import smtplib from email.mime.text import MLMEText from email.utils import formaddr msg = MIMEText('信息',"plain","utf-8") msg["From"] = formataddr(["发件人","xxxxxx@163.com"]) msg["To"] = formataddr(["收件人","xxxxxxxx@qq.com"]) msg["Subject"] = "标题" server = smtplib.SMTP ("smtp.163.com",25) server.login("xxxxxx@163.com","密码") server.sendmail("xxxxxx@163.com",["xxxxxxxx@qq.com",],msg.as_string()) server.quit() user_input = input("请输入角色:") if user_input =="管理员": send_email() elif user_input =="管理员": send_email() elif user_input =="管理员": send_email()
-
函数的基本结构 and 参数
def nnn(u): n[11,22,33,44] print(n[u]) nnn(0) def func(max_range): result = [] while True: if len(result) ==0: result.append(1) elif len(result) == 1: result.append(1) else: val = result[-1] + result[-2] if val > max_range: dreak result.append(val) return result v = func(100) print(v) def write_file(file_path,content="\n"): #换行 def read_file(file_path,num=1): #只读第一行 def fuync(*args): #*args 可以传n个参数 print(args) #传的值是元组 func(1) func(1,2) func(1,2,3) def fuync(*args): #*args 可以传n个参数 print(args) func((11,22,33,44,55)) func(*(11,22,33,44,55)) def fuync(**kwargs): #**kwargs 只能是指定传参 print(kwargs) #它传的参是字典 func(k1=1,k2=2) func(**{"K1":"V2","K2":"V3"}) def fuync(*args,**kwargs): print(args,kwargs) func(1,2,3,4,5,{"K1":"V2","K2":"V3"}) #如果要想给value设置默认值是空列表 #不推荐 def func(data,value=[]): pass #推荐 def func(data,value=None): if not value: value = [] #补充:对于函数的默认值慎用可变类型。
-
getattr() 获取对象的属性
getattr(object, name [, defalut]) """ 获取对象object名为name的特性,如果object不包含名为name的特性,将会抛出AttributeError异常;如果不包含名为name的特性 且提供default参数,将返回default。 参数object:对象 参数name:对象的特性名 参数default:缺省返回值 """
6.1 全与局变量
-
global,找全局里面的数据;nonlocal,找上一级的数据
name = "老男孩" def func(): name = "alex" def inner(): global name print(name) name = 999 inner() print(name) func() name = "老男孩" def func(): name = "alex" def inner(): nonlocal name print(name) name = 999 inner() print(name) func()
6.2 匿名函数呀
-
用lambda来实现的
#定义一个简单的函数将他赋给func5传入两个值进行判断。 func5 = lambda n1, n2: n1 if n1 > n2 else n2 v = func5(7, 1) print(v) def func5(n1,n2): if n1>n2: return n1 else: return n2 v = func5(5,3) print(v) v = [] def f(x): b = v.append(x) return b n = f("nnnnnnn") print(n) f = lambda x:x.split("l") v1 = f("alex") print(v1)
-
函数可以做返回值
def func(): print(123) def dar(): return func v =dar() print(v())
6.3 快用闭包呀
-
闭包是用到函数可以返回函数的特性所实现的
#不是闭包 def func1(name): def inner1(): return 123 return inner #是闭包:封装值+内层函数需要使用。 def func1(name): def inner2(): print(name) return 123 return inner
6.4 用作用域呀
-
递归,函数自己调用自己。(效率低)
def func(): print(1) func() func() def func(i): print(i) func(i+1) func(1) #递归次数最大1000 #在cmd里打开python解释器,调用sys模块(import sys),查看所有(dir(sys)),找到getrecursionlimit并调用(sys.getrecursionlimit())
-
函数执行的流程分析(函数到底是谁创建的?)
-
闭包概念:为函数创建一块区域并为其维护自己数据,以后执行时方便调用。[应用场景:装饰器/SQLAIchemy源码]
7.练习题呀
-
翻页
''' 要求: 每页显示10条数据 让用户输入要查看的页面:页码 ''' user_list = [] for i in range(1,836): temp = {"NAME":"你李少妻-%s" %i,"email":"123%s@qq.com"%i } user_list.append(temp) #数据总条数 total_count = len(user_list) #每页显示10条 per_page_count = 10 #总页码数 max_page_num,a = divmod(total_count,per_page_count) if a>0: max_page_num += 1 while True: pager = int(input(">>>")) if pager <1 or pager > max_page_num: print("页码不合法,必须是1~%s" %max_page_num) else: start = (pager-1) * per_page_count end = pager * per_page_count data = user_list[start:end] for item in data: print(item)
-
将ip转换为二进制在转换为十进制
def transformation_ip(ip):return [(bin(int(i)).replace("0b","").rjust(8,"0")) for i in ip.split(".")] print(transformation_ip(input(">>>"))[0])
中级阶段
1.基本使用
-
主文件
if __name__ == "__main__" page.pager()
-
如果你想将a和b的值调换,python有一个写法
a=1 b=2 a,b = b,a
-
斐波那契数列
num1 = 0 num2 = 1 while True: print(num2) num1,num2 = num2,num1+num2
-
对于包的定义:
-
py2:文件见中必须有__ init __.py。
-
py3:不需要__ init __.py
-
推荐大家以后写代码时,都要加上此文件。
-
2.用模块呀
-
模块基本知识
-
内置模块,python内部提供的功能。
import sys print(sys.atgv)
-
第三方模块,下载/安装/使用。
#把pip.exe所在的目录添加到环境变量中。 #https://pypi.org pip install 要安装的模块名称 #pip install xlrd 模块会被安装到c:/python39/lib/site-packages
-
python36 -m pip install –upgrade pip
-
-
自定义模块
# xxx.py def f1(): print("f1") def f2(): print("f2") # r1.py #掉用自定义模块中的功能 import xxx xxx.f1() xxx.f2()
-
导入模块
import abc from abc import asc from abc import * from abc import asc as a
-
模块路径
import os import sys base_dir = os.path.dirname (os.path.dirname(os.path.abspath(__file__))) sys.path.append(base_dir)
2.1 md5
-
将字符串加密
def get_md5(data) import hashlib #hai si lei buo obj = hashlib.md5() #md5 加密 obj.update(data.encode("utf-8")) #要加密的字符串,以压缩格式 result = obj.hexdigest() return result
-
加盐
def get_md5(data) import hashlib #hai si lei buo obj = hashlib.md5("sdfjsdkljg".encode("utf-8")) #md5 加密,默认在想要加密的前面加上MD5后面的字符串 obj.update(data.encode("utf-8")) #要加密的字符串,以压缩格式 result = obj.hexdigest() return result
-
示例
import hashlib user_list = [] def get_md5(data) obj = hashlib.md5("sdfjsdkljg".encode("utf-8")) obj.update(data.encode("utf-8")) result = obj.hexdigest() return result def register(): print("请创建账户") while True: user = input("请输入用户名") if user =="n": return pwd = input("请输入密码") temp = {"username":user,"password":get_md5(pwd)} user_list.append(temp) def login(): print("用户登录") user = input("请输入用户名:") pwd = input("请输入密码:") for item in user_list: if item["username"] == user and item["password"] == get_md5(pwd): return True register() result = login() if result: print("成功") else: print("失败")
-
密码不显示(只能在终端中用)
import getpass #gai te pa si pwd = getpass.getpass("请输入密码:") if pwd == "123": print("正确")
2.2 $sys
-
基本使用
import sys sys.argv() # 显示文件名 sys.path() # 默认python去导入模块时,会按照sys.path中的路径挨个查找,sys是解释器相关的数据:递归次数/引用次数 sys.exit(0) # sys模块里的exit方法,作用终止程序 a = [11,22,33] B = a print(sys.getrefcount(a)) # a被调用的次数,获取一个值的应用计数 v1 = sys.getrecursionlimit() # python默认支持的递归数量 sys.stdout.write("sdfjl") print("sdjfl\r",end="") # \n 换行、\t 制表符、\r 回到当前行的起始位置 import time for i in range(1,101): msg = "%s%%\r" %i print(msg,end="") time.sleep(0.05) # 然程序在这多执行0.05秒
-
模块参数
import sys #获取用户执行脚本时,传入的参数。 #c:\sjldj\sldjf.exe d:/djks/dslkf/d.py d:/sdklf #sys.argv = [d:/djks/dslkf/d.py ,d:/sdklf] path = sys.argv[1] import shutil shutil.rmtree(path)#删除path的所有文件 sys.path
2.3 $$os
-
基本使用
import os os.stat(file_path).st_size # 获取文件大小 v = r"d:\code\ksd.mp4" # r是转义,遇到\n\t\r当作普通的字符串处理 os.listdir(path) # 查看一个目录下所有的[第一层] os.walk(path) # 查看一个目录下所有的[所有层] os.remane("name","name2") # 重命名 os.mkdir(path) # 创建目录 os.makedirs(path) # 创建文件夹 os.getcwd() # 获取当前路径 os.chdir(path) # 修改当前路劲 os.listdir(path) # 查看路径下的所有文件 # os.path.xxx() # os.path下的方法 os.path.join(path,path,path) # 路径拼接 os.path.abspath(path) # "."代表当前的绝对路径,".\\path"代表当前的相对路径,返回path规范化的绝对路径。 os.path.isabs(path) # 查看一个路劲是相对路径还是绝对路径,绝对True。 os.path.relpath(path,start) # 将绝对路径转为相对 os.path.basename(path) # 获取路径中的最后一段 os.path.dirname(path) # 获取路径中除最后一段的所有路劲 os.path.split(path) # 将路径分割 os.path.getsize(path) # 查看路径中文件的字节大小 os.path.exists(path) # 查看路径是否存在 os.path.isfile(path_file) # 查看文件是否存在并且是一个文件 os.path.isdir(path) # 查看路径是否存在并且是一个文件夹 os.path.exists(path) # 查看路径的闪存盘是否于电脑连接 os.path.commonprefix(list_path) # 返回列表元素中共有路径 os.path.normcase(path) # 在Linux和Mac下,该函数会原样返回path,在win下会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠 os.path.normpath(path) # 规范化路径 os.path.splitdrive(path) # 返回元组,元组两个元素盘符和路径。 os.path.splitext(path_file) # 返回元组,元组两个元素路径和扩展名。 os.path.getatime(path) # 文件或者目录的最后存取时间 os.path.getmtime(path) # 文件或者目录的最后修改时间
2.4 shutil
-
基本使用
import shutil shutil.rmtree("test") # 删除目录 shutil.move("zz","bb") # 重命名 shutil.make_archive("zzh","zip","b:\") # 压缩文件 shutil.unpack_archive("zzh.zip",extract_dir=r"b:\",format="zip") # 解压文件
-
练习题
import os import shutil from datetime import dateime ctime = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") #1/压缩lizhongwei文件夹 zip #2/放到code目录(默认不存在) #3/将文件解压到d:\x1目录中。 if not os.path.exists("code"): os.makedirs("code") shutil.make_archive(os.path.join("code",ctime),"zip","d:\code\slkj\lizhongwei") file_path = os.path.join("code",ctime)+".zip" shutil.unjpack_arbhive(file_path,r"d:\x1","zip")
2.5 time
-
UTC/GMT:世界时间;本地时间:本地时区时间。
-
基本使用
import time time.time() # 时间戳:1970-1-1 00:00 time.sleep(10),等待秒数。 # ##############获取datetime格式时间 v1 = datetime.now() # 当前本地时间 # 当前东7区时间 tz = timezone(timedelta(hours=7)) v2 = datetime.now(tz) v3 = datetime.utcomw() #当前UTC时间 # ##########把datetime格式转换成字符串 v1 = datetime.now() val = v1.strftime("%Y-%m-%d %H:%M:%S") # ##############字符串转成datetime v1 = datetime.strptime("2011-11-11","%Y-%m-%d") # #################datetime时间的加减 v1 = datetime.strptime("2011-11-11","%Y-%m-%d") v2 = v1 - timedelta(days=140) date = v2.strftime("%Y-%m-%d") # ############### 时间戳和datetime关系 ctime = time.time() v1 = datetime.fromtimestamp(ctime) v1 = datetime.now() val = v1.timestamp()
2.6 json
-
json是一个特殊的字符串,
-
json和pickle
-
json,优点:所有语言通用;缺点:只能序列化基本的数据类型list/dict/int…
-
pickle,优点:python中所有的东西都被他序列化(socke对象);缺点:序列化的内容只有python认识。
-
loads,字符串转换回
v = {1,2,3,4} val = pickle.dumps(v) print(val) data = pickle.loads(val) print(data,type(data))
-
-
基本使用
import json v = {1,2,3,4} f = open ("x.xt",mode="wb") val = pickle.dump(v,f) # 第一个转换第二个写入 f.close # ################################## f = open ("x.xt",mode="rb") data = pickle.load(f) # 转换并读出 f.close v = [12,3,4,{"k1","v1"},True,"asdg"] v1 = json.dumps(v) # 序列化,将python的值转换为json格式的字符串。 v = "[3,4,{"k1","v1"},True,"asdg"]" v1 = json.loads(v) # 反序列化,将python的值转换为json格式的字符串。
-
示例
import requests import json response = requests.get("https://wwww sdl.com") data = json.loads(response) print(type(data)) print(data) # ############################### import requests response = requests.get("https://www.runoob.com/python3/python3-tutorial.html") print(type(response)) print(response) with open("b.html", mode="wb",)as f: for i in response: f.write(i)
3.用三器呀
3.1 装饰器
-
装饰器:在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能。
-
函数伪装装饰器
def func(arg): #创建函数func并传参arg def inner(): #在func函数里面创建函数inner print("before") #在inner里面打印字符串"before" v = arg() #将arg里面的函数运行并赋给v print("after") #在inner里面打印字符串"after" return v #在inner里面返回v的值 return inner #在func里面返回inner #装饰器就是在不改变index的值的情况下添加"before"和"after" def index(): #创建函数index peint("123") #在函数index里面打印"123"字符串 return "666" #在index里面返回字符串"666" index = func(index) #调用func函数并传入index函数 index() #调用index函数
-
真正的装饰器
def func(arg): def inner(): print("before") v = arg() print("after") return v return inner #第一步:执行func函数并将下面的函数参数传递,相当于:func(index) #第二步:将func的返回值重新赋值给下面的函数名。index = func(index) @func #装饰器 def index(): peint("123") return "666" index() def x(func): def inner(): return func() return inner @f def index(): pass # ###################################### # 然你理解没意义的一段代码 def x(func): # 2 运行x函数并创建inner函数 def inner(a1,a2): # 5 运行inner函数并传入两个值 return func() # 6调用func函数就是index函数 return inner # 3 返回inner函数并将 # inner赋给index(index = innder) @x # 1 0调用x函数并吧index当做参数传给x def index(): # 7 运行index函数 pass index(1,2) # 4 调用index函数index就是inner函数并传入两个实参 # 不管有几个参数都可以用的装饰器 def x1(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner @x1(1) def f1(): pass @x1 def f2(a1): pass
-
装饰器建议写法:
def x1(func): def inner(*args,**kwargs): data = func(*args,**kwargs) return data return inner
-
示例
#如何查看一个路径是否存在? import os result = os.path.exists("路径地址") # result为True,则表示路径存在。 # result为False,则表示路径不存在。 # ###################################### def wrapper(func): def inner(*atgs,**kwargs): #检测路径是否存在 path = args[0] #路径不存在就执行判断下面命令 if not os.path.exists(path): print("路径不存在") return None result = func(*atgs,**kwargs) return result return inner @wrapper def read_userinfo(path): file_obj = open(path,mode="r",encoding="utf-8") data = file_obj.read() file_obj.close() return data content = read_userinfo("/usr/bin/xxx/xxx") print(content) import time def wrapper(func): def inner(): start_time = time.time() #获取当前时间 v = func() end_time = time.time() #获取当前时间 print(start_time-end_time) return v return inner @wrapper def func1(): time.sleep(2) #等待两秒时间 print(123) def func2(): time.sleep(1) #等待两秒时间 print(123) def func3(): time.sleep(1.5) #等待两秒时间 print(123) func1() #加参数 def func(arg): def inner(*args,**kwargs): print("before") v = arg(*args,**kwargs) print("after") return v return inner @func def index(): peint("123") return "666" index("yidn")
3.2 迭代器
-
迭代器,帮助你对某种对象(str/list/tuple/dict/set类创建的对象)中的元素进行逐一获取。
v1 = iter([11,2,2,3,]) # 列表转换成迭代器 v2 = v1.__iter__() v2.all() # 接受一个迭代器,如果迭代器里有一个元素为真,那么返回True,否则返回False v2.any() # 接受一个迭代器,如果迭代器里有一个元素为真,那么返回True,否则返回False try: val = v1.__next__() # 反复调用,迭代器想要获取每个值 except Stoplteration as e: # 直到报错:Stoplteration错误,表示已经迭代完毕 pass
-
如何判别一个对象是否是迭代器:内部是否有__ next__方法。
-
可迭代对象是内部具有__ iter__()方法并且可以被for循环。
3.3 生成器
-
生成器函数(内部是否包含yield)
def func(): print("你好") yield 1 print("1") yield 2 print("3") yield(3) print("4") # 函数内部代码不会执行,返回一个生成器对象。 v1 = func() #生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。 for item in v1: print(item) ################################################################# count = 1 def func(): while True: yield count count += 1 val = func() for item in val: print(item)
-
示例
def func(): """ 分批去读取文件中的内容,将文件的内容返回给调用者。 :return: """ cursor = 0 while True: f = open("dd",'r',encoding = "utf-8") f.seek(cursor) data_list[] for i in range(10): ilne = f.readline() if not line: return ata_list.append(line) cursor = f.tell() f.close() for row in data_list: yield row
-
总结:
-
函数中如果存在yield,那么该函数就是一个生成器函数,调用生成器函数会返回一个生成器,生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会返回执行。
-
迭代器,对可迭代对象的元素进行逐一获取,迭代器对象的内部都有一个next方法,用于以一个个获取数据。
-
生成器,函数内部有yield则就是生成器函数,调用函数并返回一个生成器,循环生成器时,则函数内部代码才会执行。
-
4.推导式呀
-
列表推导式
vals = [i for i in "alex"] v1 = [i for i in "alex"] v2 = [i+100 for i in range(10)] v3 = [ 99 if i>5else 66 for i in range(10)] def func(): print(123) v4 = [func for i in range(10)] v5 = [lambda :100 for i in range(10)] def num(): return [lambda x:i*x for i in range(4)] print([m(2) for m in num()]) v9 = [i for i in range(10) if i > 5]
-
集合推导式
v1 = { i for i in "alex"}
-
字典推导式
v1 = {"k"+str(i):i for i in range(10)}
5.异常处理
-
基本使用
def func(c): try: return a.strip() #e里面保存的是报错信息 except Exception as e: pass return False v = func("alex") if not v: print("函数执行失败") else: print("结果是",v)
-
练习题
# 1.写函数,函数接受一个列表,请将列表中的元素每个都 +100 def func(arg): result = [] for item in arg: if item.isdecimal(): result.append(int(item)+100) return result # 2.写函数去,接受一个列表。列表中都是url,请访问每个地址并获取结果。 import requests def func(url_list): result = [] try: for url in url_list: response = requests.get(url) result.append(response.text) except Exception as e: pass return result
6.面向对象
-
类和对象,类是具有相同属性的摸具,对象有摸具创造具有相同的属性和方法。
-
三大特性,封装、继承、多态,python原生支持多态,崇尚鸭子模型。由于python函数传参时,无序指定类型:
def func(arg):# arg可以是多种类型,只要其中有send方法即可。 arg.send()
-
编写面向对象程序,归类+提取公共值
-
self到底是谁,self参数是python帮助我们自动传递(就是自己)。
-
如果执行面向对象中的方法时,前面需要有一个对象:xxx.func()
class Foo: def f1 (self): pass def f2(self): self.f1() obj = Foo() obj.f1()
-
python支持多继承
def __init__(self,name): #构造方法
-
经典类和新式类
-
新式类在py2中,如果自己的前辈要有人继承object,那么此类就是新式类。
-
py3经典类和新式类的查照成员的顺序不一致。
# 经典类是一条道走到黑(深度优先),会按照继承关系,先在自己这寻找,找不到后去父类中找,只找继承父类的第一个,直到第一代,会回来再去找第二个父类。 print(Foo.__mrc__) # 新式类是由c3算法实现
-
-
基本使用
class abc(obj): def func(self,name): print(name) return 123 def func2(self,name): print(name) return 456 #调用类中的方法 obj = abc() #1.创建该类的对象 result = obj.func("alex") #2.通过对象调用方法 print(result)
-
对象的作用,存储一些值,以后方便使用。
class File: def read(self): with open(self.xxxx,mode="r",encoding="utf-8") as f: data = f.read() return data def write(self,content): with open(self.xxxx,mode="w",encoding="utf-8") as f: data = f.write(content) #实例化了一个File类的对象 obj1 = File() #在对象中写了一个xxxx = "test.log" obj1.xxxx = "test.txt" #通过对象调用类中的read方法,read方法中的self就是obj。 obj1.write("alex") obj1.read() class Person: #初始化方法(构造方法),给对象的内部做初始化。 def __init__(self,n,a,g): self.name = n self.age = a self.gender = g def show(self): temp = "我是%s,年龄%s,性别%s" % (self.name,self.age,self.gender,) print(temp) #类()实例化对象,自动执行此类中的__init__方法。 p1 = Person("里",12,"男") p1.show()
-
总结:将数据封装到对象,方便使用。
6.1 成员三类
-
说明
class Foo: #方法 def __init__(self,name): #实例变量/字段 self.name = name #方法 def func(self): pass # obj,Foo类的对象 # obj,Foo类的实例 obj = Foo("holle")
1.变量
-
实例变量(字段),公有和私有实例变量(字段)
class Foo: def __init__(self,name): self.__name = name # 私有实例变量,就是在变量前面加上两个下划线(私有字段) self.age = 123 def func(self): print(self.__name) obj = Foo("holle") print(obj.__name) # obj.__name 无法访问 obj.func() # 找个人内部的人访问
-
类变量(静态字段),公有和私有类变量(静态变量)
class Foo: #类变量(静态字段) country = "中国" def __init__(self,name): #实例变量(字段) self.name = name obj1 = Foo("holle") obj2 = Foo("你好")
-
准则
-
实例变量(字段)访问时,使用对象访问,即:obj1.name
-
类变量(静态字段)访问时,使用类访问,即:Foo。country实在不方便时,(才使用对象)
-
什么时候用类变量?当所有对象中有共同的字段时则要改都改要删都删时,可以将 实例变量(字段)提取到 类变量(静态字段)
-
2.方法
-
实例方法
class Foo(object): def __init__(self,name): self.name = name #实例方法 def func(self): print(self.name)
-
静态方法
class Foo(object): #静态方法,如果方法无需使用对象中封装的值,那么就可以使用静态方法 @staticmethod def display(): print("666") Foo.display()
-
类方法
class Foo(object): @classmethod def show(cls,x1,x2): print(x1,x2) Foo.show(1,8)
-
总结
-
定义时:方法上方写:@classmethod,方法的参数:至少有一个cls参数
-
执行时:类名.方法名() #默认会将当前类传到参数中。
-
什么时候用?如果在方法中会使用到当前类,你们就可以使用方法。
-
3.属性
-
写法
class Foo(object): @property def start(self): return 1 @proprety def end(self): return 10 obj = Foo() print(obj.start) print(obj.end) class Foo(object): def __init__(self,age): self.age = age def display(self): print(self.age) data_list = [Foo(8),Foo(9)] for i in data_list: #在print的时候先执行方法,在执行对象 print(i.display(),i.age)
-
总结:
-
编写时:方法上方写@property,方法参数:只有一个self
-
调用时:无序加括号 对象.方法
-
应用场景:对于简单的方法,当无需传参则有返回值时,可以使用@property
-
6.2 其他成员
-
主动调用其他类的成员
# Base.实例方法(自己传self),与继承无关 class Base(object): def f1(self): print("5") class Foo(object): def f1(self): print("3") Base.f1(self) obj = Foo() obj.f1() # 按照类的继承顺序 class Base(object): def f1(self): print("5") class Foo(Base): def f1(self): print("3") super().f1() # 找下一个同名方法 obj = Foo() obj.f1() ########################### class Foo(object): def f1(self): super().f1() print("5") class Bar(Base ): def f1(self): print("3") class Info(Foo,Bar): pass obj = Info() obj.f1()
-
特殊成员
class Foo(object): def __init__(self,a1,a2): self.a1 = a1 self.a2 = a2 def __call__(self,*args,**kwargs): print(111,args,kwargs) def __getitem__(self,item): print(item) return 8 def __setitem__(self,key,value): print(key,value,111) def __delitem__(self,key): print(key) def __add__(self,other): return self.a1 + other.a2 def __enter__(self): print(1111) return 999 def __exit__(self,exc_type,exc_val,exc_tb): print(2222) # 1.类名() 自动执行__init__ obj = Foo(1,2) # 2.对象() 自动执行__call__ obj(5,2,k1=122) #3.对象[xx] 自动执行__getitem__ ret = obj["yu"] print(ret) #4.对象["xx"] = 123 自动执行__setitem__ obj["k1"]=123 #5.del 对象["sss"] 自动执行__delitem__ del obj["uuu"] #6.对象+对象 自动执行__add__ obj1 = Foo(1,2) obj2 = Foo(88,99) ret = obj2 = obj1 print(ret) #7.with 对象 自动执行__enter__进入,__exit__退出 obj = Foo with obj as f: print(f) print("内部") # ################################# #8.真正的构造方法 class Foo(object): def __init__(self,a1,a2):#初始化方法 self.a1 = a1 self.a2 = a2 def __new__(cls,*args,**kwargs):#构造方法 v1 = object.__new__(cls)#python内部创建一个当前类的对象(创建时内部是空的)。 print(v1) return v1 obj = Foo(1,2) print(obj) class Foo(object): def __init__(self): pass def func(self): pass #查看obj时返回"F1" def __str__(self): return "F1" obj = Foo() print(obj,type(obj)) class Foo(object): def __init__(self,name,age): self.name = name self.age = age def func(self): pass def __iter__(self): return iter([11,22,33,4]) """ 如果想要把不可迭代对象 -> 可迭代对象 1.在类中定义__iter__方法 2.iter 内部返回一个迭代器 """ obj = Foo("楼上的",99) for item in obj1: print(item) _ _dict _ _ # 获取封装值 _ _doc _ _ # 打印类注释
6.3 类的有关
-
issubclass and isinstance
class Base(object): pass class Foo(Base): pass class Bar(Foo): pass print(issubclass(Bar,Base)) # 检查第一个参数是否是第二个参数的子类,是True,不是False obj = Foo() print(issubclass(obj,Foo)) # 检查第一个参数(对象)是否是第二个参数(类)的实例(包含父类),是True,不是False print(type(obj)) # 获取当前对象是由那个类创建。
-
next and send
def a(): print('aaa') p = yield '123' # p1是send传过来的 print('bbb') r = a() print(next(r)) # next获得yield后面的值 r.send('hello') # send将值传入yield前面的变量
-
约束
class BaseMessage(object): def send(self): """ 必须继承BaseMessage,然后其中必须编写send方法,用于完成具体业务逻辑。 raise NotInplementedError(".send() 必须被重写。") """ raise NotInplementedError(".send() 必须被重写。") # BaseMessage类用于约束,约束其派生类:保证派生类中必须编写send方法,不然执行可能就会报错。 class BaseMessage(object): def send(self,x1): raise NotImplementedError(".send() 必须被重写。") class Email(BaseMessage): def send(self,x1): print("发送邮箱") obj = Email() obj.send(1)
-
总结
-
什么是接口以及作用?接口是一种数据类型,主要用于约束派生类中必须实现指定的方法,python中不存在,java和c# 中是存在的。
-
python中使用过什么类约束呢?抽象类+抽象方法,编写上麻烦,人为主动抛出异常
-
约束时,抛出的异常是否可以用其他的?不专业:raise Exception(“.send() 必须被重写.”),专业:raise NotImplementedError(“.send() 必须被重写.”)
-
7.用三闲呀
7.1 error
-
自定义异常用于,各种异常。
#知识点:如何自定义异常类? class MyException(Exception): def __init__(self,code,msg): self.code = code self.msg = msg try: #知识点:主动抛出异常 raise MyException(1000,"操作异常") except KeyError as obj: print(obj,1111) except MyException as obj: #知识点:捕获异常 print(obj,2222) except Exception as obj: print(obj,3333)
7.2 日志
-
用的不多,了解即可。
import logging logger = logging.basicConfig(filename="xxx.txt" fornat="%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S" level=30) logging.debug("x1") #10 #测试 logging.info("x2") #20 #正常 logging.warning("x3") #30 #警告 logging.error("x4") #40 #报错 logging.critical("x5") #50 #严重错误 logging.log(10,"x6") #60 #自定义日志 #filename,"文件名或文件路径"fornat,datefmt"asctime时间 - name用户名 - levelname级别 - module当前文件名: %message文件内容"时间,level=级别 import logging logger = logging.basicConfig(filename="xxx.txt" fornat="%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S" level=30) import traceback def func(): try: a = a + 1 except Exception as e: #获取当前错误的堆栈信息 msg = traceback.format_exc() logging.error(msg) func()
-
自定义日志
import logging # 创建一个操作日志的对象logger(依赖FileHandler) file_handler = logging.FileHandler('l1.log', 'a', encoding='utf-8') file_handler.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")) logger1 = logging.Logger('s1', level=logging.ERROR) logger1.addHandler(file_handler) logger1.error('123123123')
7.3 正则
-
在实际开发中常用查找某些复杂规则的字符串的需要,这时候就可以使用正则表达式。通用性强。
-
匹配Regex对象
import re phoneNumRegex = re.compile(r"\d\d\d-\d\d\d-\d\d\d") #创建一个Regex对象. mo = phoneNumRegex.search("My number is 145-126-187.") #将Regex和要匹配的字符串进行匹配,匹配满足条件的第一个 mo = phoneNumRegex.findall("My number is 145-126-187 or 568-874-589.") #将Regex和要匹配的字符串进行匹配,匹配满足条件的所有返回list mo = phoneNumRegex.sub("000-000-000","My number is 145-126-187.") #将Regex和要匹配的字符串进行匹配,匹配满足条件后进行替换 print(mo.group()) #获取匹配的数据
-
正则表达式就是记录文本规则的代码,正则表达式需要用到re模块
import re result = re.match(正则表达式,要匹配的字符串) #使用match方法进行匹配 result.group() #提取数据,如果正则中分过组,可以加入数字参数获取每个小组.
-
单个字符匹配
. #匹配任意1个字符(除\n) [] #匹配[]中列举的字符 \d #匹配数字 0~1 \D #匹配非数字 \s #匹配空白 \S #匹配非空白 \w #匹配非特殊字符,a~z/A~Z/0~9/_/汉字 \W #匹配特殊字符
-
多个字符匹配
* #匹配前一个字符出现0或n次 + #匹配前一个字符出现1或n次 ? #匹配前一个字符出现0或1次 {m} #匹配前一个字符出现m次 {m,n}#匹配前一个字符出现从m到n次
-
匹配开和尾
^ #匹配字符串开头 $ #匹配字符串结尾
-
匹配分组
| #匹配左右任意一个表达式 (ab) #将括号中字符作为一个分组 \num #引用分组num匹配到的字符 (?p<name>) #分组起别名 (?P=name) #引用别名为name分组匹配到的字符串
8.练习题呀
-
进度条
#导入模块os import os #获取文件的总大小(字节) file_size = os.stat("asdlkfjsldjf.mp4").st_size # 2.一点一点的读取文件 read_size = 0 with open("asdlkfjsldjf.mp4",mode="rb") as f1: while read_size < file_size: chunk = f1.read(1024) #每次最多去读取1024字节 read_size += len(chunk) val = int(read_size / file_size * 100) print("%s%%\r" %val,end="")
-
商品管理
def goods(): """ 商品管理 :return: """ func_dict = {"1":goods_list,"2":search_goods," 3":create_goods} while True: print("1,商品列表;2.模糊搜索,3.求人信息") num = input("请选择序号(N/n):") if num.upper() =="n": return func = func_dict.get(num) if not func: print("输入错误,请重新输入!") continue func()
高级阶段
1.基础知识
-
架构有:CS架构(Client/Server)、浏览器:BS架构(Broeser/Server)
-
如何实现相互通信,编写两个软件,软件之间相互通信、两个人直接连接 (网线)。
-
TCP和UDP
-
TCP (Transmission Control Protocol)可靠的、面向连接的协议、传输效率低全双工通信、面向字节流。使用TCP的应用:web浏览器;电子邮件、文件传输程序。
-
UDP(User Datagram Prolocol)不可靠的,无连接的服务,传输效率高,一对一,一对多,多对一,多对多,面向报文,静最大努力服务,无堵塞控制。使用UDP的应用:域名系统(DNS);视频流;IP语音。
-
一个及其联网需要有一个ip、子网掩码、网关、DNS。
-
局域网内:广播、单播、广播风暴、arp协议
-
总结:
-
相互通信本质发送二进制,交换机用于连接局域网中的设备,通过ipconfig查看自己的内网IP
-
DHCP,自动为局域网内容电脑分配ip;网关,路由器中连接交换机的口;ip 4个点分的十进制表示
-
DNS
-
域名:名称.一级.二级:端口\文件夹\文件.html
-
问题来了,域名和ip的对应关系在哪里?
-
本地:
-
win本地电脑:c:\windows\System32\drvers\etc\hosts(11.11.11.11 liyongqiang.com)
-
Linux/Mac电脑:/etc/hosts
-
-
DNS服务器:全球顶级DNS服务器13台:www.luffycity.com 47.95.64.113
-
-
-
网络基础
-
端口,是什么?为什么要有?
-
端口是为了将同一个电脑上的不同程序进行隔离。
-
总范围1 – 65535,但是1 – 1024已经被系统程序占了。
-
-
-
国际标准化组织(ISO/OSI)
-
7层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
-
5层:应用层(表示层/会话层)、传输层、网络层、数据链路层、物理层
-
4层:应用层(应用层/表示层/会话层)、传输层、网络层、物理层(数据链路层/物理层)
-
-
TCP三次握手/四次挥手
-
socket客户端向服务端发起连接请求:请求连接、允许连接、连接成功
-
服务端和客户端端来连接:请求断开连接、正在整理数据、允许断开连接、程序断开完成
-
补充:断开连接时,反应到代码上:抛出异常/发送空内容
-
-
操作系统/应用程序
-
硬件:硬盘、cpu、主板、显卡、内存、电源
-
装系统(软件),系统就是一个由程序员写出来软件,该软件用于控制计算机的硬件,让它们之间进行相互配合。
-
安软件(安装应用程序),qq、百度云、pycharm
-
-
并发和并行:并发,伪,由于执行速度特别快,人感觉不到迟钝;并行,真,创建10个人同时操作。
-
到底什么是线程?什么是进程?python之际没有,python中调用的操作系统的线程和进程。
import threading print("666") def func(arg): print(arg) t = threading.Thread(target=func) t.start() print("end")
-
线程:工作的最小单元,共享进程中所有的资源,每个线程可以分担一些任务,最终完成最后和结果。
-
进程:独立开辟内存,进程之间的数据隔离
-
总结
-
程序员写好代码在操作系统上运行(依赖解释器)
-
python多线程情况下:计算密集型操作:效率低。(GIL锁)、IO操作:效率高
-
python多进程的情况下:计算密集型操作:效率高(浪费资源)、IO操作:效率高(浪费资源)
-
以后写python时:IO密集型用多线程,文件/输入输出/socket网络通信、计算密集型用多进程
-
JAVA多线程情况下:计算密集型操作:效率高、IO操作:效率高
-
python中线程和进程(GIL锁)GIL锁,全局解释器锁。用于限制一个进程中同一时刻只有一个线程被cpu调动。扩展:默认GIL锁在执行100个CPU指令(过期时间)
-
2.基本网络
2.1 socket
-
服务端
import socket # 创建服务端socket对象 server = socket.socket() # 绑定IP和端口 server.bind(('192.168.13.155',8000)) # 后边可以等5个人 server.listen(5) print('服务端准备开始接收客户端的连接') # 等待客户端来连接,如果没人来就傻傻的等待。 # conn是客户端和服务端连接的对象(伞),服务端以后要通过该对象进行收发数据。 # addr是客户端的地址信息。 # #### 阻塞,只有有客户端进行连接,则获取客户端连接然后开始进行通信。 conn,addr = server.accept() print('已经有人连接上了,客户端信息:',conn,addr) # 通过对象去获取(王晓东通过伞给我发送的消息) # 1024表示:服务端通过(伞)获取数据时,一次性最多拿1024字节。 data = conn.recv(1024) print('已经有人发来消息了',data) # 服务端通过连接对象(伞)给客户端回复了一个消息。 conn.send(b'stop') # 与客户端断开连接(放开那把伞) conn.close() # 关闭服务端的服务 server.close()
-
客户端
import socket client = socket.socket() #王晓东向服务端发起连接请求(递伞) #堵塞,去连接,直到连接成功后才会继续向下走。 client.connect(("xx.xx.xx.xx",8000)) #连接上服务端后,向服务端发送消息 client.send(b"hello") #万晓东等待服务端给它发送消息 data = client.recv(1024) print(data) #关闭自己 client.close()
-
基于socket模块实现网络通信
-
为什么要网络通信发送的是字节?而不是字符串?py2,send/recv 都是字节、py3,send/recv 都是字符串。
-
服务端:accept,阻塞:等待客户端来连接、recv,阻塞:等待客户端发来数据。
-
客户端:connect,阻塞:一直在连接,值到连接成功才往下运行其他代码、recv,阻塞:等待服务器发来数据。
2.2 subprocess/struct
-
标准输入
import subprocess res=subprocess.Popen("dir",#指定命令名 shell=True, stderr=subprocess.PIPE, #错误输出 stdout=subprocess.PIPE,) #接收系统返回的值 print(res.stdout.read().decode("gbk")) #输出接收到的值以“gbk”
-
包判定计算大小
import struct #i模式把123456压缩,四个字节,如果大于就报错 # 最大是2的31次方减一 header_pack=struct.pack("i",2147483647)#压包 print(header_pack) obj = struct.unpack("i",beader_pack)#解包 print(obj)
2.3 socketserver
-
快速server模块
import socketserver #所有的网络通信都在这里面执行 class Myserver(socketserver.BaseRequestHandler): def handle(self): whlie True: try: print("等待") #之前的conn现在是self.request data = self.request.recv(1024) if data == b"t" break response = data + b"sb" self.request.send(response) except Exception as e: break self.request.close() #创建服务端加ip,端口,类名 #1.创建socket对象 2.self.socket.bind() 3.self.socket.listen(5) server = socketserver.ThreadingTCPServer(("127.0.0.1",8899),Myserver) #等待连接连接成功后会从类开始执行 server.serve_forever()
3.用三程呀
3.1 线程
-
使用threading实现
import threading import time def func(arg): #获取当前执行该函数的线程的对象 t = thredding.current_thread() #根据当前线程对象获取当前线程名称 name = t.getName() time.sleep(2) print(name,arg) t1 = threading.Thread(target=func,args=(3,)) #为True就让主进程不等待直接执行完 #为False就让主进程等待子进程,默认时等待的 t1.setDaemon(True) #设置名 t1.setName("哇哈哈") t1.start #无参数,让主线程在这里等着,等到子线程t1执行完毕,才可以继续往下走。 #有参数,让主线程在这里最多等待n秒,无论是否执行完毕,会继续往下走。 t1.join(2)
-
自定义创建多线程
import socket import threading def task(conn): data = conn.recv(1024) print(data) conn.close() server = socket.socket() server.bind(("127.0.0.1,8822")) server.listen(5) while True: conn,addr = server.accept() t = threading.Thread(target=task,args=(conn,)) t.start()
-
面向对象多线程
import therading #1 def func(arg): print(arg) t1 = threading.Thread(target=func,args=(11,)) t1.start #2 class MyThread(threading.Thread): def run(self): print(1111,self._args,self._kwargs) t1 = MyThread(args=(11,)) t1.start() t2 = MyThread(args=(22,)) t2.start()
-
uuid模块
import uuid 随机生成字符串 v = str(uuid.uuid4()) print(v)
-
requests模块
#需要下载 pip install requests #爬图片 import reqquest import uuid import threading url_list = [] def task(url): """ 1.DNS解析,根据域名解析出ip 2.创建socket客户端 sk = socket.socket() 3.向服务端发起连接请求 sk.connect() 4.发起数据(我要图片) sk.send(...) 5.接收数据 sk.recv(8096) """ #帮你创建连接然后域名解析,然后然他给你发图片 ret = requests.get(url) #请求下载下来的图片 file_name = str(uuid.uuid4()) + ".jpg" with open(file_name,mode="wb")as f: f.write(ret.content) for url in url_list: t = threading.Thread(target=task,args=(url,)) t.start()
-
锁的初步认识
import time import threading lock = threading.RLock() n = 10 def task(i): print("这段代码不加锁") lock.acquire()#加锁 global n print("当前线程",i,"读取到的n值为:",n) n = i time.sleep(1) print("当前线程",i,"修改n值为:",n) lock.release()#解锁 for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start()
-
总结
-
应用程序/进程/线程的关系?
-
为什么要创建线程?由于线程时cpu工作的最小单元,创建线程可以利用多核优势实现并行操作(JAVA/C#)
-
为什么要创建进程?进程和进程之间做数据隔离(Java/c#)
-
python
-
python中存在一个GIL锁,造成:多线程无法利用多核优势、解决:开多进程处理(浪费资源)
-
线程的创建:Thread、MyTread
-
其他:join、setDeanon、setName、threading.current_thread()
-
锁,获得、释放
-
-
python的GIL锁
-
python内置的一个全局解释器锁,锁的作用就是保证同一刻一个进程中只有一个线程可以被cpu调用。
-
为什么有这把GIL锁?python语言的创始人在开发这门语言时,目的快速把语言开发出来,如果加上GIL锁(c语言加锁)
-
-
进程和线程的区别?线程,cpu工作的最小单元。、进程,线程提供一个资源共享的空间、一个进程中默认是有一个主线程。
-
进程和线程的使用准则:计算密集型:多进程、IO密集型:多线程
-
线程创建的越多越好吗?不好,线程之间切换时,要做上下文管理。
-
1.线程池
-
基本使用
from concurrent.futures import ThreadPoolExecutor import time def task(a1,a2): time.sleep(2) print(a1,a2) #创建了一个线程池(最多5个线程) pool = ThreadPoolExecutor(5) for i in range(40): #去线程池中申请一个线程,让线程执行task函数 pool.submit(task,i,8)
-
生产者和消费者模型
# by luffycity.com import time import queue import threading q = queue.Queue() # 线程安全 def producer(id): """ 生产者 :return: """ while True: time.sleep(2) q.put('包子') # 存值 print('厨师%s 生产了一个包子' %id ) for i in range(1,4): t = threading.Thread(target=producer,args=(i,)) t.start() def consumer(id): """ 消费者 :return: """ while True: time.sleep(1) v1 = q.get() # 取值 print('顾客 %s 吃了一个包子' % id) for i in range(1,3): t = threading.Thread(target=consumer,args=(i,)) t.start()
-
生产者消费者模型解决了什么问题?不用一直等待的问题。
2.独立空间
-
作用:内部自动为每个线程维护一个空间(字典),用于当前存储属于自己的值。保证线程之间的数据隔离。
-
基本使用
import time import threading v = threading.local() def func(arg): #内部会为当前线程创建一个空间用于储存:phone=自己的值 v.phone = arg time.sleep(2) print(v.phone,arg)#去当前线程自己空间获值 for i in range(10): t = threading.Thread(target=func,args=(i,)) t.start()
-
local原理
import time import threading def func(arg): ident = threading.get_ident() DATA_DICT[ident] = arg time.sleep(2) print(DATA_DICT[ident],arg) for i in range(10): t = threading.Thread(target=func,args=(i,)) t.start()
-
实例
# by luffycity.com """ 以后:Flask框架内部看到源码 上下文管理 """ import time import threading INFO = {} class Local(object): def __getattr__(self, item): ident = threading.get_ident() return INFO[ident][item] def __setattr__(self, key, value): ident = threading.get_ident() if ident in INFO: INFO[ident][key] = value else: INFO[ident] = {key:value} obj = Local() def func(arg): obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1) time.sleep(2) print(obj.phone,arg) for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start()
3.2 进程
-
基本使用
#mac系统不会报错#win系统会报错 def task(arg): print(arg) for i in range(10): p = multiprocessing.Process(target=task,args=(i,)) p.start() #这样win系统就不会报错了 def task(arg): print(arg) if __name__ =="__main__": for i in range(10): p = multiprocessing.Process(target=task,args=(i,)) p.start()
-
不共享
import multiprocssing import threading import queue data_list = [] def task(arg): data_list.append(arg) print(data_list) def run(): for i in range(10): p = multiprocessing.Process(target=task,args=(i,)) p.start() if __name__ =="__main__": run()
-
进程常用功能
import multiprocssing import threading import queue def task(arg): time.sleep(2) print(arg) def run(): for i in range(10): p = multiprocessing.Process(target=task,args=(i,)) p.start() p.join()#等待进程 if __name__ =="__main__": run() ########################### def task(arg): time.sleep(2) print(arg) def run(): for i in range(10): p = multiprocessing.Process(target=task,args=(i,)) p.daemon = False#True不等子进程,相反 p.start() if __name__ =="__main__": run() ################### def task(arg): #获取当前进程 p = multiprocessing.current_process() print(p.name) time.sleep(2) print(arg) def run(): for i in range(10): p = multiprocessing.Process(target=task,args=(i,)) p.name = "pp1"#给进程命名 p.start() if __name__ =="__main__": run() ######################### def task(arg): #获取当前进程 p = multiprocessing.current_process() print(p.ident)#打印当前进程 time.sleep(2) print(arg) def run(): for i in range(10): p = multiprocessing.Process(target=task,args=(i,)) p.name = "pp1"#给进程命名 p.start() if __name__ =="__main__": run()
-
面向对象创建进程
import multiprocssing import threading import queue class MyProcess(multiprocessing.Process): def task(arg): def run(self): print("当前进程",multiprocessing.current_process()) def run(): p.MyProcess() p.start() if __name__ =="__main__": run()
-
进程间的数据共享:先进先出 队列、先进后出 站,进程间的共享
#linux这样写 import multiprocessing q = multiprocessing.Queue() def task(arg,q): q.put(arg) def run(): for i in range(10): p = multiprocessing.Process(target=task,args=(i,q,)) while True: v = q.get() print(v) if __name__ == "__main__" run() ############################ #windows这样写 import multiprocessing def task(arg,q): q.put(arg) if __name__ == "__main__" q = multiprocessing.Queue() for i in range(10): p = multiprocessing.Process(target=task,args=(i,q,)) while True: v = q.get() print(v)
-
进程间的共享 Manager
#linux这样写 import multiprocessing q = multiprocessing.Manager() dic = m.dict() def task(arg,q): dic[arg] = 100 def run(): for i in range(10): p = multiprocessing.Process(target=task,args=(i,q,)) p.start() input(">>>") print(dic.values()) if __name__ == "__main__" run() ############################ #windows这样写 import multiprocessing def task(arg,q): dic[arg] = 100 if __name__ == "__main__" m = multiprocessing.Manager() for i in range(10): p = multiprocessing.Process(target=task,args=(i,m,)) p.join() print(dic) ######################2 import multiprocessing def task(arg,q): dic[arg] = 100 if __name__ == "__main__" m = multiprocessing.Manager() dic = m.dict() process_list[] for i in range(10): p = multiprocessing.Process(target=task,args=(i,cic)) p.start() process_list.append(p) while True: count = 0 for p in process_list: if not p.is_alive():#True是还在执行,Fasle是已执行完 cunt +=1 if count == len(process_list): break print(dic)
-
进程锁
import time import multiprocessing lock = multiprocessing.RLock() def task(arg): print("鬼子来了") lock.acquire() time.sleep(2) print(arg) lock.release() if __name__ == "__main__": p1 = multiprocessing.Process(target=task,args=1) p1.start() p2 = multiprocessing.Process(target=task,args=1) p2.start()
1.进程池
-
基本使用
import time from comcurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor # #############################线程池 def task (arg): time.sleep(2) print(arg) if __name__ == "__main__": pool = ThreadPoolExecutor(5) for i in range(10): pool.submit(task,i) # #############################进程池 def task (arg): time.sleep(2) print(arg) if __name__ == "__main__": pool = ProcessPoolExecutor(5) for i in range(10): pool.submit(task,i)
3.3 协程
-
进程线程,操作系统中存在
-
协程,是有程序员创造出来的一个不是真实存在的东西;是微线程,对一个线程进程分片,是的线程在代码块之间进行来回切换执行,而不是在原来逐行执行。
pip install gevent pip install greenlet import greenlet def f1(): print(11) #跳到f2执行f2函数 gr2.switch() print(22) def f2(): print(33) #跳到f1执行f1函数 gr1.switch() print(44) #协程 gr1 gr1 = greenlet.greenlet(f1) gr2 = greenlet.greenlet(f2) gr1.switch()
-
IO多路复用+协程
from gevent import monkey monkey.patch_all()#以后代码中遇到IO都会自动执行greenlet的switch进行切换 import requests import gevent def get_page(url): ret = requests.get(url) print(url,ret.content) gevent.joinall([gevent.spawn(get_page,"https://www.python.org/")]) #一个协程
-
总结
-
什么是协程?协程也可以成为微线程,就是开发者控制线程执行流程,控制先执行某段代码然后切换到另外执行代码。
-
协程可以调高并发吗?执行自己本身无法实现并发,协程+IO切换性能提高。
-
进程、线程、协程,协程+IO切换:基于事件循环的异步非阻塞框架:Twisted、手动实现协程:yield关键字生成器
def f1(): print(11) #第一次执行到这卡住再将1赋给send x1 = yield 1 #接收v1.send(999)的值赋给x1 print(x1,22) #返回一个二 yield 2 print(33) def f2(): print(44) yield print(55) yield print(66) #第一次执行接受yield返回的值赋给ret ret = v1.send(None) pritn(v1) #发送一个值,接受一个值 v = v1.send(999)
-
4.快用锁呀
-
线程安全,多线程操作时,内部会让所有线程排队处理。如:list/dict/Queue
-
需求,创建100个线程:锁,把自己的添加到列表中,在读取列表的最后一个;解锁。
1 lock
-
基本使用
import threading import time v = [] #创建锁 lock = threading.Lock() def func(arg): #上锁 lock.acquire() v.append(arg) time.sleep(0.01) m = v[-1] print(arg,m) #解锁 lock.release() for i in range(10): t = treading.Thread(target=func,args=(i,)) t.start()
2 RLock
-
基本使用
import threading import time v = [] #创建锁 lock = threading.RLock() def func(arg): #上锁 lock.acquire() v.append(arg) time.sleep(0.01) m = v[-1] print(arg,m) #解锁 lock.release() for i in range(10): t = treading.Thread(target=func,args=(i,)) t.start()
3 信号量
-
基本使用
import threading import time v = [] #创建锁 lock = threading.Lock() #一次执行多个 lock = threading.BoundedSemaphore(3) def func(arg): #上锁 lock.acquire() v.append(arg) time.sleep(0.01) m = v[-1] print(arg,m) #解锁 lock.release() for i in range(10): t = treading.Thread(target=func,args=(i,)) t.start()
4 Condition
-
基本使用
import threading import time v = [] #创建锁 lock = threading.Condition() #一次执行多个 lock = threading.BoundedSemaphore(3) def func(arg): #上锁 lock.acquire() v.append(arg) time.sleep(0.01) m = v[-1] print(arg,m) for i in range(10): t = treading.Thread(target=func,args=(i,)) t.start() while True: inp = int(input(">>>")) lock.release() #解锁 lock.release() ##########################2 #一次执行多个 def xxx(): print("111") input(">>>") return True def func(arg): print("222") lok.wait_for(xxx)#锁住了,只有条件为True,才往下走1,一个 print(arg) time.sleep(1) for i in range(10): t = treading.Thread(target=func,args=(i,)) t.start()
5 Event
-
基本使用
import time import threading lock = threading.Event() def func(arg): print('线程来了') lock.wait() # 加锁:红灯 print(arg) for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start() input(">>>>") lock.set() # 绿灯 lock.clear() # 再次变红灯 for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start() input(">>>>") lock.set()
4.发送请求
-
基本使用
import socket import sequests #方式一 ret = requests.get("https://www.baidu.com/s?wd=alex") #方式二 cloent = socket.socket() #和百度创建连接:阻塞 client.connect(("www.baidu.com",80)) #问百度你要什么? client.sendall(b"GET /s?wd=alex http/1.1\r\nhost:www.baidu.com\r\n\r\n") #我等着百度给我的回复 chunk_list = [] while True: chunk = client.recv(1024) if not chunk: break chunk_list.append(chunk) body = b"".join(chunk_list) print(body.decode("utf-8"))
5.非阻塞呀
-
基本使用
import socket #方式二 cloent = socket.socket() cloent.setblocking(False)#将原来阻塞的变成非阻塞 #和百度创建连接:阻塞 try: client.connect(("www.baidu.com",80)) #问百度你要什么? except BlockingIOError as e: pass client.sendall(b"GET /s?wd=alex http/1.1\r\nhost:www.baidu.com\r\n\r\n") #我等着百度给我的回复 chunk_list = [] while True: chunk = client.recv(1024)#将原来阻塞的变成非阻塞 if not chunk: break chunk_list.append(chunk) body = b"".join(chunk_list) print(body.decode("utf-8")) ########################################### #单线程的并发 import socket import select #方式二 cloent = socket.socket() cloent.setblocking(False)#将原来阻塞的变成非阻塞 #和百度创建连接:阻塞 try: client.connect(("www.baidu.com",80)) #问百度你要什么? except BlockingIOError as e: pass socket_list = [client1,client2,client3] conn_list = [client1,client2,client3] while True: rlist,wlist,elist = select.select(socket_list,conn_list,[],0.005) #如果有数据返回就把他放到rlist,如果有连接成功就把他放到wlist,如果有异常就把他放到[]中 #socket_list是检测是否服务端给我返回数据了 可读 #conn_list检测其中的所有socket是否已经和服务端连接成功 可写 #[]获取异常 #0.005是最多等0.005秒 for sk in wlist: if sk == client1: sk.sendall(b"GET /s?wd=alex http/1.1\r\nhost:www.baidu.com\r\n\r\n") else: sk.sendall(b"GET /s?wd=alex http/1.1\r\nhost:www.baidu.com\r\n\r\n") for sk in rlist: chunk_list = [] while True: try: chunk = sk.recv(8096) if not chunk: break chunk_list.append(chunk) except BlockingIOError as e: break body = b"".join(chunk_list) print(body.decode("utf-8")) sk.close() socket_list.remove(sk) if not socket_list: break
-
IO多路复用作用:检测多个socket是否已经发生变化(是否已经连接完成/是否已经获取数据)(可读/可写)
-
IO多路复用,socket的会堵塞、Twisted ,基于事件循环实现的异步非堵塞框架,异步:执行完某个人物后自动调用我给他的函数。
#单线程的并发 import socket import select #方式二 cloent = socket.socket() cloent.setblocking(False)#将原来阻塞的变成非阻塞 #和百度创建连接:阻塞 try: client.connect(("www.baidu.com",80)) #问百度你要什么? except BlockingIOError as e: pass class Foo(object): def __init__(self,sk): self.sk = sk def fileno(self): return self.sk.fileno() """ 1.select.select(socket_list,conn_list,[],0.005) select监听的socket_list/conn_list内部会调用列表中每一个值的fileno方法,获取该返回值并去系统中检测。 2.方式一: select.select([client1,]) """ socket_list = [Foo(client1),Foo(client2),Foo(client3)] conn_list = [client1,client2,client3] while True: rlist,wlist,elist = select.select(socket_list,conn_list,[],0.005) #如果有数据返回就把他放到rlist,如果有连接成功就把他放到wlist,如果有异常就把他放到[]中 #socket_list是检测是否服务端给我返回数据了 可读 #conn_list检测其中的所有socket是否已经和服务端连接成功 可写 #[]获取异常 #0.005是最多等0.005秒 for sk in wlist: if sk == client1: sk.sendall(b"GET /s?wd=alex http/1.1\r\nhost:www.baidu.com\r\n\r\n") else: sk.sendall(b"GET /s?wd=alex http/1.1\r\nhost:www.baidu.com\r\n\r\n") for sk in rlist: chunk_list = [] while True: try: chunk = sk.recv(8096) if not chunk: break chunk_list.append(chunk) except BlockingIOError as e: break body = b"".join(chunk_list) print(body.decode("utf-8")) sk.close() socket_list.remove(sk) if not socket_list: break
-
实现非阻塞
import socket import select class Req(object): def __init__(self,sk,func): self.sock = sk self.func = func def fileno(self): return self.sock.fileno() class Nb(object): def __init__(self): self.conn_list = [] self.socket_list = [] def add(self,url,func): client = socket.socket() client.setblocking(False) # 非阻塞 try: client.connect((url, 80)) except BlockingIOError as e: pass obj = Req(client,func) self.conn_list.append(obj) self.socket_list.append(obj) def run(self): while True: rlist,wlist,elist = select.select(self.socket_list,self.conn_list,[],0.005) # wlist中表示已经连接成功的req对象 for sk in wlist: # 发生变换的req对象 sk.sock.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n') self.conn_list.remove(sk) for sk in rlist: chunk_list = [] while True: try: chunk = sk.sock.recv(8096) if not chunk: break chunk_list.append(chunk) except BlockingIOError as e: break body = b''.join(chunk_list) # print(body.decode('utf-8')) sk.func(body) sk.sock.close() self.socket_list.remove(sk) if not self.socket_list: break def baidu_repsonse(body): print('百度下载结果:',body) def sogou_repsonse(body): print('搜狗下载结果:', body) def oldboyedu_repsonse(body): print('老男孩下载结果:', body) t1 = Nb() t1.add('www.baidu.com',baidu_repsonse) t1.add('www.sogou.com',sogou_repsonse) t1.add('www.oldboyedu.com',oldboyedu_repsonse) t1.run()
-
总结
-
socket默认是否阻塞的?阻塞体现在哪里?
-
如何让socket编程非阻塞?
-
IO多路复用作用?
-
检测多个socket是否发生变化。
-
操作系统检测socket是否发生变化,有三种模式:
-
select:做多1024个socket;循环去检测。
-
poll:不限制监听socket个数;循环去检测(水平触发)。
-
epoll:不限制监听socket个数;回调方式(边缘触发)。
-
-
python模块:select.select、select.epoll
-
-
提高并发方案:多进程、多线程、异步非堵塞模块(Twisted)scrapy框架(单线程完成并发)
-
9.练习题呀
-
解释器和编译器的区别?编译型先把代码编译成机器码 , 计算机寄存器去运行、解释型边解释边执行。
-
py2/py3
-
打印,py2中print ” xx”、py3中print(123)
-
继承,py2中经典类/新式类、py3中新式类
-
编码,py2中ascii可以修改#- * – encoding:utf-8 – * –、py3中utf-8可以修改#- * – encoding:utf-8 – * –
-
字符串,py2中unicode v = u”root” 本质上用ynicode存储、(str/bytes) v = “root” 本质用字节存储、py3中str v = “root” 本质上用ynicode存储、bytes v = b”root” 本质用字节存储
-
输入,py2中v1 = raw_input(“>>>”)、py3中v1 = input(“>>>”)
-
范围,py2中range/xrange、py3中range
-
-
练习
# Client import socket import struct sk = socket.socket() sk.connect(('127.0.0.1',8008)) while 1: cmd = input("请输入命令:") sk.send(cmd.encode('utf-8')) # 字节 if cmd=="": continue if cmd == 'exit': break # header_pack=sk.recv(4) # data_length=struct.unpack("i",header_pack)[0] # print("data_length",data_length) ''' b'xxx/xxx/xxx/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ''' data_length=int(sk.recv(1024).decode("utf8")) print("data_length",data_length) recv_data_length=0 recv_data=b"" while recv_data_length<data_length: data=sk.recv(1024) recv_data_length+=len(data) recv_data+=data print(recv_data.decode("gbk")) sk.close() # Server # by luffycity.com import socket import subprocess server = socket.socket() server.bind(('127.0.0.1',8008)) server.listen(5) while True: print("server is working.....") conn,addr = server.accept() # 字节类型 while True: # 针对window系统 try: cmd = conn.recv(1024).decode("utf8") # 阻塞 if cmd == b'exit': break res=subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, ) # print("stdout",res.stdout.read()) # print("stderr",res.stderr.read().decode("gbk")) out=res.stdout.read() err=res.stderr.read() print("out响应长度",len(out)) print("err响应长度",len(err)) if err: import struct header_pack = struct.pack("i", len(err)) conn.send(header_pack) conn.send(err) else: #构建报头 import struct header_pack=struct.pack("i",len(out)) print("header_pack",header_pack) # # 发送报头 conn.send(str(len(out)).encode("utf8")) # 发送数据 conn.send(out) except Exception as e: break conn.close()
-
练习
# Server import struct import socket import json import hashlib sock=socket.socket() sock.bind(('127.0.0.1',8800)) sock.listen(5) while 1: print("server is working....") conn,addr= sock.accept() while 1: # 接收json的打包长度 file_info_length_pack=conn.recv(4) file_info_length=struct.unpack("i",file_info_length_pack)[0] # 接收json字符串 file_info_json=conn.recv(file_info_length).decode("utf8") file_info=json.loads(file_info_json) action=file_info.get("action") filename=file_info.get("filename") filesize=file_info.get("filesize") # 循环接收文件 md5=hashlib.md5() with open("put/"+filename,"wb") as f: recv_data_length=0 while recv_data_length<filesize: data=conn.recv(1024) recv_data_length+=len(data) f.write(data) # MD5摘要 md5.update(data) print("文件总大小:%s,已成功接收%s"%(filesize,recv_data_length)) print("接收成功!") conn.send(b"OK") print(md5.hexdigest()) md5_val=md5.hexdigest() client_md5=conn.recv(1024).decode("utf8") if md5_val==client_md5: conn.send(b"203") else: conn.send(b"204") # Client import socket import os import json import struct import hashlib sock=socket.socket() sock.connect(("127.0.0.1",8800)) while 1 : cmd=input("请输入命令:") # put 111.jpg action,filename=cmd.strip().split(" ") filesize=os.path.getsize(filename) file_info={ "action": action, "filename": filename, "filesize": filesize, } file_info_json=json.dumps(file_info).encode("utf8") ret=struct.pack("i",len(file_info_json)) # 发送 file_info_json的打包长度 sock.send(ret) # 发送 file_info_json字节串 sock.send(file_info_json) # 发送 文件数据 md5=hashlib.md5() with open(filename,"rb") as f: for line in f: sock.send(line) md5.update(line) data=sock.recv(1024) print(md5.hexdigest()) md5_val=md5.hexdigest() sock.send(md5_val.encode("utf8")) is_valid=sock.recv(1024).decode('utf8') if is_valid=="203": print("文件完整!") else: print("文件上传失败!")
-
进度条
import time def func(size,total_size): val = int(size/total_size * 100) time.sleep(0.2) print("\r%s%%|%" %(val,"*"*val,),end="") for i in range(100): func(i,100)
-
读取文件大小
import os size = os.stat(r"sadf\asdf\d\").st_size print(size)