目录前端
计算机的主要组成部分时主板、CPU、硬盘、内存及一些外设设备组成。java
操做系统(OS),是最接近物理硬件的系统软件。主要用来协调、控制、分配计算机硬件资源,使计算机各组件能够发挥最优性能。python
软件是运行于操做系统之上的应用程序。mysql
计算机语言主要是有解释器/编译器/虚拟机,再加上语法规则构成用来开发其余软件的工具。解释型语言,一般是由解释器边解释边执行的计算机语言,例如:python、ruby、PHP、perl。编译型语言,一般是由编译器编译整个代码文件,生成计算机能够识别的文件,交由计算机处理。linux
首先,在官网下载py2与py3,2,3版本有不少不兼容全部会存在两个版本共存的问题。目前,mac、ubuntu等一些系统已经内置了python2版本。git
为了开发须要,咱们须要下载并安装python3。用于开发的软件,一般安装版本通常是找次新版本进行安装。安装pycharm IDE 开发工具。程序员
环境变量的功能,及其配置。环境变量分为,用户环境变量(只对当前用户生效)和系统环境变量(全部用户均有效)。主要用于终端使用,不须要输入python解释器的完整路径,只要输入pythonx 就可以使用。web
PATH:方便用户在终端执行程序。即,将可执行程序所在的目录添加到环境变量,之后直接调用便可。正则表达式
mac的环境变量在~/.bash_profile文件中。一般在安装的时候python会自动生成环境变量,无需手动配置。redis
当前,比较通用的编码有ASCII、Unicode、UTF-八、GB23十二、GBK。因为计算机最初使用的是ASCII编码,因此其余编码必须兼容ASCII码。
ASCII
ASCII码,7bits表示一个字符,最高位用0表示,后来IBM进行扩展,造成8bit扩展的ASCII码。包含全部英文字母和经常使用的字符,最多能够表示127或256种。
Unicode
Unicode(万国码),随着计算机的普及,计算机须要兼容多国语言,Unicode编码应运而生。32bits表示一个字符,总共能够表示2**32种不一样的符号,远远超出目前全部文字及字符,迄今使用21bits。通用的特色换来的是存储空间的浪费,通常只用于计算机内部处理计算。
utf-8
为弥补unicode的不足,utf-8针对unicode进行压缩和优化,去掉前面多余的0,只保留有效部分。完整保留ASCII码,欧洲文字通常用2bytes表示,中文通常用3bytes表示。
GBK
全称是GB2312-80《信息交换用汉字编码字符集 基本集》,1980年发布,是中文信息处理的国家标准,在大陆及海外使用简体中文的地区(如新加坡等)是强制使用的惟一中文编码。
中文使用2bytes表示。GBK,是对GB2312的扩展,又称GBK大字符集,简而言之就是全部亚洲文字的双字节字符。
# IDE:统一使用UTF-8, 全局和项目均如此
变量的主要做用是为了屡次重复使用方便。
# 查看python关键字 import keyword keyword.kwlist
常量:不容许修改的值,python中只是约定
Python语句中通常以新行做为语句的结束符。
可是咱们可使用斜杠( )将一行的语句分为多行显示,以下所示:
total = item_one + \ item_two + \ item_three
input("按下 enter 键退出,其余任意键显示...\n") # 不换行输出 print(x, end='') print(y, end='')
a = b = c = 1 a, b, c = 1, 2, "john"
# 若是在指定的序列中找到值返回 True,不然返回 False in # 若是在指定的序列中找到值返回 False,不然返回 True not in
is # is 是判断两个标识符是否是引用自一个对象 x is y 相似 id(x) == id(y) , 若是引用的是同一个对象则返回 True,不然返回 False is not # is not 是判断两个标识符是否是引用自不一样对象 x is not y 相似 id(a) != id(b)。若是引用的不是同一个对象则返回结果 True,不然返回 False。
执行Python代码时,若是导入了其余的 .py 文件,那么,执行过程当中会自动生成一个与其同名的 .pyc 文件,该文件就是Python解释器编译以后产生的字节码。
字节码(Bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。字节码是一种中间码。它比机器码更抽象,须要直译器转译后才能成为机器码的中间代码。
机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。机器码是电脑CPU直接读取运行的机器指令。
ps:代码通过编译能够产生字节码;字节码经过反编译也能够获得代码。
v = u'henry' print(v, type(v)) # unicode类型 # py2 py3 数据类型对应关系 unicode<class> <--> str eg.u'alex' <--> 'alex' str <--> bytes eg.'alex' <--> b'alex
Py2 | Py3 | ||
---|---|---|---|
1 | 字符串类型不一样 | ||
2 | py2py3默认解释器编码 | ASCII | UTF-8 |
3 | 输入输出 | raw_input() ; print | input() ; print() |
4 | int / long | int 和 long,除法只保留整数 | 只用int,除法保留小数 |
5 | range/xrange | range/xrange | 只有range,至关于py2的xrange |
6 | info.keys,info.values,info .items | 数据类型是list | 数据类型是<class 'dict_keys'> |
7 | map/filter | 数据类型是list | 返回的是iterator,能够list()查看<map object at 0x108bfc668> |
8 | reduce | 内置 | 移到functools |
9 | 模块和包 | 须要__init__.py | — |
10 | 经典类和新式类 | 同时拥有 | 只有新式类 |
# None 无操做 # bytes 类
# 只有str 能够强转 s = '99' print(type(int(s)))
# bool 布尔,主要用于条件判断。 # None, 0 , '', [], {}, set() # 以上都是False
str操做经常使用的 14 (9+5) 种 1.upper/lower 2.isdigit/isdecimal 3.strip 4.replace 5.split 6.startswith/endswith 7.encode 8.format 9.join
# 大小写转换 s = 'Henry' print(s.upper(), s.lower())
# 判断是不是数字 s1 = '123' s2 = '12.3' print(s1.isdigit(), s2.isdigit()) # True Flase # isdecimal只判断是不是整数
# 默认去除两边空格+ \n + \t s = ' asdfgh, ' print('-->', s.strip(), '<--') print('-->', s.strip().strip(','), '<--')
# repalce 中的 a 和 b 必须是str类型, n 必须是int类型 s = 'adsafga' print(s.replace('a', '666')) print(s.replace('a', '666', 1))
# str的分割 s = 'henry_echo_elaine_' li = s.split('_') print(li) # 分割后的元素永远比分隔符号多一个
# 判断开始/结束位置是不是指定元素 s = 'abghjkdc' print(s.startswith('ab'), s.endswith('cd')) # True Flase
# 若是使用格式化输入,打印%须要使用 %% # %s,%d :表示占位符 # way1 一般用于函数 "***{0}***{1}**".format(a, b) # % (a, ) :这里表示tuple,建议加逗号 # way2 "***%s, ***%s***" % (a, b,)
# 示例 # way1 '{0} ***{1}'.format(a, b) a = 'abcd' b = '666' s = '{0} ***{1}'.format(a, b) print(s) # way2 s1 = '%s***%s' % (a, b,) print(s1)
扩展使用示例:
# %s ,只能是tuple msg = '我是%s, 年龄%s' % ('alex', 19) msg = '我是%(name)s, 年龄%(age)s' % {'name': 'alex', 'age': 19} # format格式化 v1 = '我是{name}, 年龄{age}'.format(name = 'alex', age = 18) v1 = '我是{name}, 年龄{age}'.format(** {'name': 'alex', 'age': 19}) v2 = '我是{0}, 年龄{1}'.format('alex', 18) v2 = '我是{0}, 年龄{1}'.format(*('alex', 18) )
# 指定编码类型 s = '你好' print(s.encode('utf-8')) # 6个字节 print( s.encode('gbk')) # 4个字节
# 用于循环加入指定字符 # s 必须是iterable # s 但是str,list,tuple,dict,set(str + 容器类) # s 中元素值必须是str类型 '_'.join(s)
# 示例 # 指定元素循环链接str中的元素 s = 'henry' print('_'.join(s)) # 下划线链接个字符
# 返回s长度 s = '1234567890' print(len(s)) # 10
# 索引取值 s = '123456789' print(s[3]) # 4
s = '123456789' print(s[3:5]) # 45
# 根据step进行切片 s = '123456789' print(s[3::2]) # 468
s = '123456789' for i in s: print(i)
list操做目前一共有15(8+7)种, 1.append 2.insert 3.remove 4.pop 5.clear 6.reverse 7.sort 8.extend
# 任意类型数据,li操做不能直接放在print()中 li = [1, 2, 3, 4, 5, 6] li.append('666') print(li) li.append(['henry']) print(li)
# 按照index位置插入指定内容 li = [1, 2, 3, 4, 5, 6] li.insert(3, 'henry') print(li)
# 删除指定list中的元素 li = ['aa', 'a', 'aacde'] li.remove('aa') print(li) li.remove('bb') print(li) # 会报错
# 按index删除list中的元素 li = [1, 2, 3, 4, 5, 6] li.pop() print(li) li.pop(3) print(li)
# 清空list中的全部元素 li = [1, 2, 3, 4, 5, 6] li.clear() print(li)
# 反转list中的元素 li = [1, 2, 3, 4, 5, 6] li.reverse() print(li)
# reverse = True 从大到小 # 只能是同一类型的元素 # dict,tuple不支持排序 li = [6, 2, 3, 1, 5, 4] li.sort() print(li) li = ['ba', 'ab', 'c', 'd'] li.sort(reverse=True) print(li) li = [[6], [2, 3], [1, 5, 4]] li.sort() print(li) li = [(6, 2, 3, 1, 5, 4)] li.sort() print(li)
# 把s中的元素,循环取出,逐个追加到list中 # s能够是str, list, tuple, dict, set # dict只取keys 追加到list中 s = 'henry' li = [1, 2, 3, 4, 5, 6] li.extend(s) print(li) s = ['a', 'b', 'c', 'd'] li.extend(s) print(li)
li = [1, 2, 3, 4, 5, 6] print(len(li))
li = [1, 2, 3, 4, 5, 6] print(li[2])
li = [1, 2, 3, 4, 5, 6] print(li[2:5])
li = [1, 2, 3, 4, 5, 6] print(li[2::2])
li = [1, 2, 3, 4, 5, 6] for i in li: print(i)
# 使用index修改,若是只是一个值,则正常修改 li = [1, 2, 3, 4, 5, 6] li[2] = 'henry' print(li) # 使用index修改,若是是多个值,认为是一个tuple li[2] = 'a', 'b', 'c' print(li) # 使用切片[]修改,则循环取值加入 li[2:3] = 'a', 'b', 'c' print(li)
# del 也不能放在print()里面 li = [1, 2, 3, 4, 5, 6] del li[2] print(li) del li[2:] print(li
# 没有独有操做,目前只有5种 # tuple里,最后一个值最好加一个 逗号 ,以区别于运算符
t = (1, 2, 3,) print(len(t))
t = (1, 2, 3,) print(t[2])
t = (1, 2, 3,) print(t[1:])
t = (1, 2, 3, 4, 5, 6, 7, 8, 9, 0) print(t[1::2])
t = (1, 2, 3, 4, 5, 6, 7, 8, 9, 0) for i int t: print(i)
dict 目前一共有 14(9 + 5) 种操做, 1.keys 2.values 3.items 4.get 5.pop 6.update 7.setdefault 8.popitem 9.clear # {key1: value1, k2:value2} # key不能重复
# 取全部key info = {1: 'henry', 2: 'echo', 3: 'eliane'} for key i info: print(key)
# 取全部value info = {1: 'henry', 2: 'echo', 3: 'eliane'} for v in info.values(): print(v)
# 取全部key值对 # 取出的是 tuple 类型 info = {1: 'henry', 2: 'echo', 3: 'eliane'} for pair in info.items(): print(pair)
# 有key则取出, 没有则返回指定 值 # 若是没有指定值,则返回 None info = {1: 'henry', 2: 'echo', 3: 'eliane'} print(info.get(1, 666)) print(info.get(4, 666))
info = {1: 'henry', 2: 'echo', 3: 'eliane'} print(info.pop(1)) print(info.pop(4))
# 只能用dict类型更新 info = {} info1 = {1: 'henry', 2: 'echo', 3: 'eliane'} info.update(info1) print(info)
# 查询key,有则取出,没有则添加 info = {1: 'henry', 2: 'echo', 3: 'eliane'} info.setdefault(4, 'hello') print(info) # 取出须要赋值给其余变量 val = info.setdefault(4, 'i hate you') print(val)
# 不能加参数,删除最后一个key值对 info = {1: 'henry', 2: 'echo', 3: 'eliane'} v = info.popitem() print(v,info) # v是tuple
# 清空全部元素 info = {1: 'henry', 2: 'echo', 3: 'eliane'} info.clear() print(info)
li = [1, 2, 3, 4, 5] info = {'a': 1, 'b': 2} v = info.fromkeys(li, 'hello') print(v, info)
info = {1: 'henry', 2: 'echo', 3: 'eliane'} print(len(info))
info = {1: 'henry', 2: 'echo', 3: 'eliane'} print(info[1])
info = {1: 'henry', 2: 'echo', 3: 'eliane'} for i in info: print(i) for v in info.values(): print(v) for pair in info.items(): print(pair)
# key同样则修改,不同则追加 info = {1: 'henry', 2: 'echo', 3: 'eliane'} info[1] = 'hello' print(info) info[4] = 'you are smart' print(info)
info = {1: 'henry', 2: 'echo', 3: 'eliane'} del info[1] print(info)
# __getitem__ set, del from collections import OrderdDict info = OrderedDict() info['k1'] = 123 info['k2'] = 456
set 目前一共有11(10 + 2)种操做,空集合用set()表示。 1.add 2.update 3.pop 4.discard 5.remove 6. clear 7.intersection 8.union 9.difference 10.symmetric_difference # 无序,不重复
s = {1, 'henry', 2, 'echo', 3, 'eliane'} s.add(5) print(s)
# 能够用str , list, tuple, dict, set, 也能够混合多种类型放入update中 s = {1, 'henry', 2, 'echo', 3, 'eliane'} s1 = {5, 6, 7, 8, 1, 2, 3} s2 = [5, 6, 7, 8, 1, 2, 3] s3 = (5, 6, 7, 8, 1, 2, 3) s4 = {5: 6, 7: 8, 1: 2} s.update(s1) print(s) s = {1, 'henry', 2, 'echo', 3, 'eliane'} s.update(s2) print(s) s = {1, 'henry', 2, 'echo', 3, 'eliane'} s.update(s3) print(s) s = {1, 'henry', 2, 'echo', 3, 'eliane'} s.update(s4) print(s)
# 随机删除,此时pop中不能有任何参数 s = {1, 'henry', 2, 'echo', 3, 'eliane'} s.pop() # 默认删除第一个元素/随机 print(s)
# 必须有一个参数,没有不报错, 不会返回值 s = {1, 'henry', 2, 'echo', 3, 'eliane'} val = s.discard(3) print(s) print(val)
# 必须有一个参数,没有会报错 s = {1, 'henry', 2, 'echo', 3, 'eliane'} s.remove(3) print(s)
s = {1, 'henry', 2, 'echo', 3, 'eliane'} s.clear() print(s)
# 取v1 和v2 的交集 v1 = {1, 'henry', 2, 'echo', 3, 'eliane'} v2 = {1, 3, 5, 7} v = v1.intersection(v2) print(v)
# 取并集 v1 = {1, 'henry', 2, 'echo', 3, 'eliane'} v2 = {1, 3, 5, 7} v = v1.union(v2) print(v)
v1 = {1, 'henry', 2, 'echo', 3, 'eliane'} v2 = {1, 3, 5, 7} v = v1.difference(v2) print(v)
v1 = {1, 'henry', 2, 'echo', 3, 'eliane'} v2 = {1, 3, 5, 7} v = v1.symmetric_difference(v2) print(v)
# 集合的运算 方法 运算法
v = {1, 'henry', 2, 'echo', 3, 'eliane'} print(len(v))
# 无序输出 v = {1, 'henry', 2, 'echo', 3, 'eliane'} for i in v: print(i)
int | bool | str | list | tuple | dict | set | |
---|---|---|---|---|---|---|---|
len | — | — | ✓ | ✓ | ✓ | ✓ | ✓ |
index | — | — | ✓ | ✓ | ✓ | ✓ | — |
切片 | — | — | ✓ | ✓ | ✓ | — | — |
step | — | — | ✓ | ✓ | ✓ | — | — |
for循环/ iterable | — | — | ✓ | ✓ | ✓ | ✓ | ✓ |
修改 | — | — | — | ✓ | — | ✓ | ✓ |
删除 | — | — | — | ✓ | — | ✓ | ✓ |
小数据池
缓存规则:
文件操做主要用来读取、修改、和建立指定文件。
f = open('文件路径',mode='r/w/a...',encoding='utf-8')
# mode= 'w' # 打开文件时,会先清空历史文件,没有则建立 f.write('a')
# mode= 'r' # way1 整个文件直接读取到RAM f.read() # 若是指定编码格式,会读出 1 个字符 # 若是是 mode= rb 会读出 1 个字节 f.read(1) # way2 按行读取文件 # 通常用于for循环中,可用来读取 GB 级别的文件 f.readline() 只读取一行 f.readlines() # 一次性加载全部内容到内存,并根据行分割成字符串 # 读取一行时也可使用 for line in v: line = line.strip('\n')
# 当对文件操做完成后必须关闭,不然不会存储到本地磁盘 f.colse() # 刷新缓冲区里任何还没写入的信息
mode常见的有r/w/a(只读/写/追加),r+/w+/a+(读写/写读/追加读),rb/wb/ab(以二进制方式进行读/写/追加),r+b/w+b/a+b。
模式 | r | r+ | w | w+ | a | a+ |
---|---|---|---|---|---|---|
读 | + | + | + | + | ||
写 | + | + | + | + | + | |
建立 | + | + | + | + | ||
覆盖 | + | + | ||||
指针在开始 | + | + | + | + | ||
指针在结尾 | + | + |
断点续传,经过终端与服务器之间的交互,找到文件断点位置,从而实现文件的单次传输。此种操做可使用file.seek(n)实现,n表示字节数。
seek(offset [,from])方法改变当前文件的位置。Offset变量表示要移动的字节数。From变量指定开始移动字节的参考位置。若是from被设为0,这意味着将文件的开头做为移动字节的参考位置。若是设为1,则使用当前的位置做为参考位置。若是它被设为2,那么该文件的末尾将做为参考位置。
# 示例 #!/usr/bin/python # -*- coding: UTF-8 -*- import os # 重命名文件test1.txt到test2.txt。 os.rename( "test1.txt", "test2.txt" )
#!/usr/bin/python # -*- coding: UTF-8 -*- import os # 删除一个已经存在的文件test2.txt os.remove("test2.txt")
v = open('a.txt',mode='a',encoding='utf-8') while True: val = input('请输入:') v.write(val) # 强制把内存中的数据,刷到硬盘中 v.flush() v.close()
v = open('a.txt', mode='a', encoding='utf-8') v1 = v.read() v.close()
# 缩进中的代码执行完毕后,自动关闭文件 with open('a.txt', mode='a', encoding='utf-8') as v: data = v.read()
Note:
# 示例1 # 文件的修改,须要先把内容读到内存,修改后再存储 with open('a.txt', mode='r', encoding='utf-8') as v: data = v.read() print(data) new_data = data.replace('a', 666) with open('a.txt', mode='w', encoding='utf-8') as v: data = v.wirte(new_data)
# 示例2 修改指定字符 # 大文件的修改 f1 = open('a.txt', mode='r', encoding='utf-8') f2 = open('b.txt', mode='r', encoding='utf-8') for line in f1: line = line.replace('a', 'b') f2.write(line) f1.close f2.close
# 一次性打开修改和关闭 with open('a.txt', mode='r', encoding='utf-8') as f1,open('b.txt', mode='r', encoding='utf-8') as f2: for line in f1.readlines(): # 或者以下写法 for line in f1: # 这种写法,也会一行行读取,包括 \n 也会单独一行读出 line = line.replace('a', 'b') f2.write(line)
以双下划线开头的 **__foo** 表明类的私有成员,以双下划线开头和结尾的 **__foo__** 表明 Python 里特殊方法专用的标识,如 init() 表明类的构造函数。
又称为三目运算
和预算符相关
val = v if v else 666 val = v or 666 # 源码中会见到
Note:为了赋值
# 简单条件赋值时使用 v = 前面 if 条件 else 后面
# 用户输入,若是是整数,则转换,不然赋值为None data = input('>>>') value = int(data) if data.isdecimal() else Non
面向过程【可读性差、可重用性差】—> 函数式编程—>面向对象
# 若是给其余人发送邮件,能够把发送程序进行封装起来,可缩减代码长度和提升重复利用性。
函数式编程
能够定义一个由本身想要功能的函数,如下是简单的规则:(5)
def functionname( parameters ): "函数_文档字符串" function_suite # 函数体 return [expression] # 默认状况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
# 函数定义 # way1 def 函数名(): # 函数体 pass # 函数的执行 函数名() # 会自动执行 # way2 # 形参能够是多个 def 函数名(形参): # 函数体 pass 函数名(实参)
形参(形式参数)与实参(实际参数)的位置关系。
def 函数名(形参): # 函数体 pass 函数名(实参)
# 无形参示例 def get_sum_list() sum = 0 for i in li: sum += i print(get_sum_list())
# 有形参示例 # 请写一个函数,函数计算列表 info = [11,22,33,44,55] 中全部元素的和。 info = [11, 22, 33, 44] def get_list_sum(li): sum = 0 for i in li: sum += i print(sum) get_list_sum(info)
def func(arg): return 9 # 返回值为9,默认为None,能够返回任何类型的数据 val = def func(v)
# 示例2 # 让用户输入一段字符串,计算字符串中有多少A,就在文件中写入多少‘echo’ def get_char_count(arg): count = 0 for i in arg: count += 1 def write_file(data): open('a.txt', mode='w', encoding='utf-8') as v: if len(data) == 0:或者 if not bool(data): return '写入失败' v.write(data) return '写入成功' print(count) content = input()
# way1 无形参,无return def fun1(): pass fun() # way2 有形参,无return def fun2(arg): pass fun2(v) # way3 无形参,有return(指定值) def fun3(): pass return 9 val = fun3(v) # way4 有形参,有return(变量) def fun4(arg1, arg2): pass return arg1 + arg2 val = fun4(v1 + v2)
# 1. 写函数,计算一个list中有多少个数字,打印,有%s个数字 # 判断数字:type(a) == int # 2. 写函数,计算一个列表中偶数索引位置的数据构形成另一个列表,并返回。 # 3. 读取文件,将文件的内容构形成指定格式的数据,并返回。 a.log文件 alex|123|18 eric|uiuf|19 ... 目标结构: a. ["alex|123|18","eric|uiuf|19"] 并返回。 b. [['alex','123','18'],['eric','uiuf','19']] c. [ {'name':'alex','pwd':'123','age':'18'}, {'name':'eric','pwd':'uiuf','age':'19'}, ]
参数传递方式分为位置传参、关键字传参、函数做为参数进行传递。
# 示例 def func(a1, a2): pass func(1, 3) func(1, [1, 2, 3])
# 示例 def func(a1, a2): pass func(a1 = 1, a2 = [1, 2, 3]) func(a1 = 1, 2 ) # 此时会报顺序错误
函数定义中,def func() 括号中能够省略、默认参数和 *args/**kwargs。
# 示例 def func(): pass
# 示例 def func(a1, a2=2): pass # 调用方法,有默认参数时,能够不用省略,采起默认值,也能够从新赋值 func(1) func(1, 3) # 默认形参时,若是默认是可变类型的须要谨慎使用
# 若是想要给values设置默认是空list def func(data, value=[]): pass # 推荐 def func(data, value=None): if not value: valu=[]
# 示例 : 能够传递任意类型数据 def func(*args): pass # [1, 2, 3]会被当成总体变成tuple中的一个元素 func(1, 2, 3, [1, 2 ,3]) # 直接赋值, [1, 2, 3]也会循环取出追加到tuple中 func(4, 5 ,6 ,*[1, 2 ,3])
# 示例 :只能经过关键字传参,或者dict赋值 def func(**kwargs): print(kwargs) # [1, 2, 3]会被当成总体变成dict中 'd': [1, 2, 3] func(a=1, b=2, c=3, d=[1, 2 ,3]) # 直接赋值, {'k1': 4, 'k2': 5}也会循环取出追加到形参的dict中 func(a=1, b=2, c=3, d=[1, 2, 3], **{'k1': 4, 'k2': 5})
变量做用域时是变量的有效做用范围,在python中函数就是一个局部做用域。因为做用域的不一样,变量的有效范围也不一样,根据做用范围能够把变量分为,全局变量和局部变量。
全局变量:可供任何函数进行使用,修改,在python文件第一层的变量。在python中通常把全局变量命名为所有大写(规范),例如:USRE_NAME = 'henry'。
局部变量:能够把函数中的变量视为局部变量。函数体中变量为函数所私有(只能被其子函数进行使用)。
# 示例1 a = 'henry' def func(): print(a) a = 123 func() # 此时使用的是全局变量, 结果是 123 # 示例2 a = 'henry' def func1(): def func2(): a = 'echo' print(a) func2() print(a) a = 123 func1() print(a) # echo 123 123
# 示例 # 对于可变变量能够进行修改 a = [1, 3, 5, 7] def fun1(): a.append('henry') fun1() print(a) # 此时a会被修改
# 两种赋值的方法 # 可使用 global 关键字对全局变量进行从新赋值 global name name = 'alex' # 给全局变量从新赋值 # 可使用 nolocal 关键字对父籍变量进行从新赋值, 在父籍找不到时,会报错 nonlocal name name = 'alex' # 给父籍变量从新赋值
# <class 'function'> def func (): pass print(type(func)) # 函数能够认为是一变量
def func(): print(123) v = fun # 指向相同的地址 v()
# 示例 def func(): print(123) v1 = [func, func, func] v2 = [func(), func(), func()] print(v1) print(v2)
def func(arg): print(arg) def show(): return 999 func(show) # 999 None
def func(): print(1,2,3) def bar(): return func v = bar() # func v()
# 10 个函数, 通常是创建字典 def func(): print('话费查询') def bar(): print('***') def base(): print('***') info = { 'f1': func, 'f2': bar, 'f3': base } choice = input('please input your choice: ') name = info.get('choice') if not name: print('输入不存在') else: name()
# 三目运算,为了解决简单的if...esle的状况 # lambda,为了解决简单函数的状况 eg: def func(a1, a2): return a1 + a2 # 能够改写为,a1 + 100 即为return 值 func = lambda a1, a2: a1 + 100
# way1 直接使用 func = lambda : 100 func = lambda a: a*10 func = lambda *args, **kwargs: len(args) + len(kwargs) # way2 使用全局变量 DATA = 100 func = lambda a: a + DATA func(1) # way3 使用父籍变量 DATA = 100 def func(): DATA = 1000 func1 = lambda a: a + DATA v = func1(1) print(v) func() # way4 使用条件判断 ######## func = lambda n1, n2: n1 if n1 > n2 else n2
# 练习1 USER_LIST = [] func1 = lambda x: USER_LIST.append(x) v1 = func1('alex') print(v1) # None print(USER_LIST) # ['alex'] # 练习2 func1 = lambda x: x.strip() v1 = func1(' alex') print(v1) # 'alex' # 练习3 func_list = [lambda x: x.strip(), lambda y: y+100, lambda x,y: x+y] v1 = func_list[0](' alex') print(v1) # 'alex'
# divmod. 练习 USER_LIST = [] for i in range(1, 836): tem = {name':'hello-%s' % i, 'email':'XXXX%s@qq.com' %s} USER_LIST.append(tem) """ 要求: 每页展现10条 根据用户输入的页码,查看 """
# base 默认为 10 v1 = '0b1101' result = int(v1, base = 2) # 转8进制 v1 = '0o1101' result = int(v1, base = 8) # 转16进制 v1 = '0x1101' result = int(v1, base = 16)
# ip 点分二进制,将十进制转为二进制并经过 . 链接ip = '192.168.12.79' ip = '192.168.12.79' li = ip.split('.') l = [] for i in li: i = int(i) i = bin(i) i = str(i).replace('0b', '') i = i.rjust(8, '0') l.append(i) s = '.'.join(l) print(s)
chr() :把int型数据,转换为unicode编码
# 生成验证码 import random # 导入一个模块 def get_random_data(length=6): data = [] for i in range(length): v = random.randint(65,90) # 获得一个随机数 data.append(v) return ' '.join(data) code = get_random_data() print(code)
map / filter / reduce(py2)/zip
# map操做的 func 是一个函数 v 必须是可迭代, v = [11, 22, 33] def func(arg): return arg + 100 result = map(func, v) # 将函数的返回值添加到空list中[111, 122, 133] print(list(result)) # 使用lambda 改写 result = map(lambda x: x+100, v) print(result) # py2直接返回 print(list(resutl)) # py3会返回一个object,可用list()查看
v = [1, 2, 3, 'welcome', 4, 'hello'] result = filter(lambda x: type(x) == int, v) # 生成新list print(list(result)
import functools v = [1, 2, 3, 4] result = functools.reduce(lambda x,y: x*y, v) print(result)
a = [1,2,3] b = [4,5,6] c = [4,5,6,7,8] zipped = zip(a,b) # 打包为元组的列表 [(1, 4), (2, 5), (3, 6)] zip(a,c) # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式 [(1, 2, 3), (4, 5, 6)] # 两组序列,转字典 list1 = ['key1','key2','key3'] list2 = ['1','2','3'] info = dict(zip(list1,list2)) print(info)
def func(name): def inner(): print(name) return inner v1 = func('henry') v1() v2 = func('echo') v2()
# 不是闭包 def func(name): def inner(): return 123 return inner # 闭包:封装值 + 内层函数须要使用 def func(name): def inner(): print(name) return 123 return inner
def func(i): print(i) func(i+1)
# 斐波那契数列 def func(a, b): print(b) func(a, a+b)
# 递归 def fun(a): if a == 5: return 100 result = func(a+1) + 10 return result v = func(1) # 注意 def fun(a): if a == 5: return 100 result = func(a+1) + 10 v = func(1)
def func(): def inner(): pass return inner v = func() print(v) # inner 函数 # ############################## def func(arg): def inner(): print(arg) return inner v1 = func(1) # 1 v2 = func(2) # 2 # ############################## def func(arg): def inner(): arg() return inner def f1(): print(123) v = fucn(f1) v() # 123 # ############################## def func(arg): def inner(): arg() return inner def f1(): print(123) return 666 v1 = func(f1) result = v1() # 执行inner函数 / f1含函数 -> 123 print(result) # None # ############################## def func(arg): def inner(): return arg() return inner def f1(): print(123) return 666 v1 = func(f1) result = v1() # 123 666
def func(arg): def inner(): print('before') v = arg() print('after') return v return inner def index(): print('123') return 666 # 示例 v1 = index() # 123 v2 = func(index) # before 123 after v3 = v2() v4 = func(index) # before 123 after index = v4 index() index = func(index) # before 123 after index()
# 第一步,执行func函数,并将下面的函数看成函数传递,至关于func(index) # 第二部,将func返回值,从新赋值为下面的函数名,index = func(index) def func(arg): def inner(): return arg() return inner @func def index(): print(123) return 666 print(index) # <function func.<locals>.inner at 0x1054a16a8>
应用示例:
# 计算函数执行时间 def wrapper(func): def inner(): start_time = time.time() func() end_time = time.time() print(end_time - start_time) return func() return inner import time @ warpper def func(): time.sleep(2) print(123) @ warpper def func(): time.sleep(1.5) print(123) # 判断用户是否登录
# 装饰器的编写(示例) def wrapper(func): # 必须有一个参数 def inner(): ret = func() return ret return inner # 应用 index = wrapper(index) @wapper def index(): pass @wapper def manage(): pass # 在执行函数,自动触发装饰器 v = index() print(v)
# 导入本目录下的其余py文件 import a a.f1() a.f2() a.f3()
def wrapper(func): def inner(*args, **kwargs): return func(*args, **kwargs) return inner
为何要加*args,**kwargs?
# 让参数统一的目的:为装饰的函数传参 def x(func): def inner(a, b): return func() return inner @x def index(): pass index(1, 2)
# 装饰器建议写法 def wrapper(function): def inner(*args, **kwargs): v = funtion(*args, **kwargs) return v return inner @wrapper def func(): pass
# 第一步:v = wrapper(9) # 第二步:ret = v(index) # 第三步:index = ret def x(counter): def wrapper(function): def inner(*args, **kwargs): v = funtion(*args, **kwargs) return v return inner return wrapper @x(9) def index(): pass
# 示例: # 写一个带参数的装饰器,实现,参数是多少,被装饰器就要执行多少次,最终返回一个list def x(*args): def wrapper(): def inner(): li = [index() for i in range(args[0])] return li return inner return wrapper @x(9) def index(): return 8 v = index() print(v)
list推导式(生成式)
vals = [i for i in 'henry'] v = [i for i in 可迭代对象 if 条件] # 知足条件生成list v = [i if i > 5 else i+1 for i in 可迭代对象 if 条件] # 知足条件生成list
# 新浪 def num(): return [lambda x: x * i for i in range(4)] print([m(2) for m in num()])
set推导式
# 知足条件生成set,会去重,条件判断能够省略 v = {i for i in 可迭代对象 if 条件}
dict推导式
# 知足条件生成dict,但须要key值和冒号:,条件判断能够省略 v = { 'k' + str(i): i for i in 可迭代对象 if 条件}
类:int ,str, list…. / bytes(b'xxx'), datetime
对象:由类建立的数据
类和对象
展现list中全部数据
v = [1, 2, 3, 4] val = iter(v) value = val.__next__() print(value)
def func(): pass func()
# 生成器函数(内部是否包含yield) def func(arg): arg = arg + 1 yield 1 yield 2 yield 100 # 函数内部代码不执行,返回一个生成器 val = func(100) # 生成器:能够被for循环的,一旦开始循环,函数内部代码就开始执行 for i in val: print(i) # 遇到第一个yield会把后面的值赋值给 i # 若是yield已经执行完毕,则意味着for循环结束
# 边使用边执行 def func(): count = 1 while True: yield count count += 1 # v 只取yield值,是一个生成器对象 v = func() for i in v: print(i) # 查看v中有哪些方法 dir(v)
class Foo(object): def __iter__(self): return iter([1, 2, 3]) yield 1 yield 2 obj = Foo(object)
def func(): print(123) n = yield('aaa') print('----->', n) yield 'bbb' data = func() next(data) v = data.send('太厉害了,直接传进去了') print(v)
# 示例:读取文件 def func(): curse = 0 while True: f = open('db','r','utf-8') f.seek(curse) data_list = [] for i in range(10): line = f.readline() if not line: return data_list.append(line) curse = f.tell() f.close for row in data_list: yield row
# redis 示例 import redis coon = redis.Redis(host='192.168.12.12')
# yield from (py3.3以后) def base(): yield 88 yield 99 def bar(): return 123 def func(): yield 1 yield from base() yield from bar() # 报错,int 不可迭代,若是可迭代,则循环取出 yield 2 yield
v1 = [i for i in range(10)] # list推导式,当即产生数据 def func(): for i in range(10): yield i v2 = func() # 与下面v2相同 v2 = (i for i in range(10)) # 生成器推导式,不会当即产生数据
# 示例1 ret = filter(lambda n: n%3==0, range(10)) print(len(list(ret))) # 4 print(len(list(ret))) # 0
# 示例2 def add(n, i): return n + i def test(): for i in range(4): yield i g = test() for n in [1, 10]: g = (add(n, i) for i in g) print(list(g)) # [20 21 22 23 24]
# 示例3 def add(n, i): return n + i def test(): for i in range(4): yield i g = test() for n in [1, 10, 5]: g = (add(n, i) for i in g) print(list(g)) # [15, 16, 17, 18]
# 示例1 try: val = input('请输入数字:') num = int(val) except Exception as e: print('操做异常')
# 示例2 import requests try: ret = requests.get('http://www.baidu.com') print(ret.text) except Exception as e: print('请求异常')
# 示例3 def func(a): try: return a.strip() except Exception as e: pass return False v = func([1, 2, 3]) print(v)
# 练习1,函数接收一个list将list中的元素每一个都加100 def func(arg): li = [] for items in arg: if items.isdecimal(): li.append(int(items) + 100) return li
# 写函数,接收一个list, 中全是url 访问地址,并获取结果 import requests def func(url_list): li = [] try: for i in url_list: reponse = requests.get(i) li.append(reponse.text) except Exception as e: pass return li func(['http://www.baidu.com', 'http://www.google.com', 'http://www.bing.com'])
# 比较异常 try 的位置不一样,效果也不一样 import requests def func(url_list): li = [] for i in url_list: try: reponse = requests.get(i) li.append(reponse.text) except Exception as e: pass return li func(['http://www.baidu.com', 'http://www.google.com', 'http://www.bing.com']) # 获得的结果是text格式的文本文档 reponse = requests.get('url', useragent:xxxxxx)
try: pass except ValueError as e: pass except IndexErro as e: pass except Exception as e: print(e) finally: print('final') # 不管对错都要执行的代码 # e 表明异常信息,是Exception类的对象,有一个错误信息 try: int('asdf') except Exception as e: print(e) try: int('asdf') except ValueError as e: print(e) try: int('asdf') except IndexError as e: print(e) # 即便遇到return 也会执行finally def func(): try: int('1') return except Exception as e: print(e) finally: print('final')
try: int('123') raise Exception('错误信息') # 主动抛出异常 except Exception as e: print(1)
# 打开一个文件, def func(): resutl = True try: with open('x.log', mode='r', encoding='utf-8') as f: data = f.read() if 'henry' not in data: raise Exception() except Exception as e: result = False return result
# 示例1 class MyException(Exception): pass try: raise MyException('haha,错了吧') except MyException as e: print(e)
class MyException(Exception): def __init__(self, message): self.message = message try: raise MyExceptoin('123') except MyException as e: print(e.message)
# test为文件夹,在当前工做目录中,jd为py文件,f1为jd中的函数 import test.jd test.jd.f1() # test为文件夹,在当前工做目录中,jd为py文件,f1为jd中的函数 from test import jd jd.f1()
# 导入(绝对导入、相对. /..导入:相对导入必须有父籍包 # import # from 模块.模块 import 模块 # from 模块.模块.模块 import 函数 # 调用:模块.函数(),函数() # 主文件:运行的文件(print(__name__)). if __name__ == '__main__
# __file__ python命令行中获取的参数 import os import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR)
分类:
# pip 安装模块 pip install module_name # 安装成功,若是导入不成功,须要重启pycharm
# a.py def f1(): pass def f2(): pass
# 调用自定义模块中的功能 import a a.f1()
内置模块目前有random,hashlib, getpass ,sys相关,os相关,shutil ,json,time&datetime, import lib, logging等 10个。
# random.randint(a, b) import random def get_random_data(length=6): data = [] for i in range(length): v = chr(random.randint(65, 90)).lower() # 获得一个随机数 data.append(v) return ' '.join(data)
摘要算法模块,密文验证/校验文件独立性
# 将指定的**str**摘要,可使用sha1/md5 # md5经常使用来文件完整性校验 # hashlib.md5()/ .update() /.hexdigest() import hashlib def get_md5(data): obj = hashlib.md5() obj.update(data.encode('utf-8')) return obj.hexdigest() val = get_md5('123') print(val)
加盐:
import hashlib def get_md5(data): obj = hashlib.md5('adsfg12fsg'.encode('utf-8')) obj.update(data.encode('utf-8')) return obj.hexdigest() val = get_md5('123') print(val)
密码不显示:
import getpass pwd = getpass.getpass('please input pwd: ') print(pwd)
import time v = time.time() # 获取从1970年开始到目前的时间,单位为秒 time.sleep(2) # 休眠时间,2秒
# 引用计数器 import sys a = [1, 2, 3] print(sys.getrefcount(a)) # python默认支持的递归数量 v = sys.getrecrusionlimit() # 输入输出,默认换行 sys.stdout.write('hello') # \n \t # \r: 回到当前行的起始位置,通常于end=‘’连用 print('123\r', end='') print('hello', end='') # 在输出的时候,回到123前,从新打印 # 应用:进度条
# sys.argv shutil # 删除 目录 的脚本, 只能是directory import sys import shutil path = sys.argv[1] shutil.rmtree(path) print('remove the %s' % path)
# sys包含python 和 工做目录 # 当前py文件所在路径会加载到 sys.path中 # pycharm也会 自动添加工做目录 和 项目路径加入 # python导入模块时默认查找路径 # 只能导入目录下的第一层文件 sys.path.append('module_path')
import os 1. 获取文件大小 fiel_size = os.stat('filename').st_size # 单位为字节 2. 读取文件 chunk_size = 1024 with open('filename', mode='rb') as f1: v = r'path' # r 表示转义,包括全部 os.path.dirname(v)
转义 v = 'al\\nex' v = r'al\nex' # 推荐
import os v = 'test.txt' path = 'user/henry/desktop' new_path = os.path.join(path, v)
# 当前目录下第一层文件 import os result = os.listdir(r'path') print(result) # 当前目录下的全部文件 import os result = os.walk(r'path') # 生成器 for a, b, c in result: for i in c: # a 是目录;b 是目录下的文件夹;c 是目录下的文件 path = os.path.join(a, i) print(path)
import shutil shutil.rmtree(r'path')
import shutil # 没有返回值 shutil.rmtree('dir_name') # 重命名,能够是文件/目录 shutil.move('file_name1', 'new_file_name') # 压缩文件(c_file_name.zip), 若是只给定文件名,压缩到py脚本所在目录 shutil.make_archive('c_file_name', 'zip', 'dir_name') # 解压文件,默认是当前路径, 指定目录不存在会建立文件目录 shutil.unpack_archive('c_file_name.zip', extra=r'dir_paths', format='zip', )
from datetime import datetime # 当前时间 ctime = datetim.now().strftime('%Y-%m-%d %H:%M:%S') # 1.压缩test文件夹 # 2.放到code目录(默认不存在) # 3.将文件解压到/User/henry/Desktop/t中
序列化:将本来的字典、列表等内容转换成一个字符串的过程就叫作序列化。
目的:
# 只能包含,int,bool,str,list,dict # 最外层必须是list/dict # json 中若是包含str,必须是 双引号 # 若是是tuple类型数据,则会转换为list - 特殊的字符串(list和dict嵌套的string) - 不一样语言间的数据交互 - 序列化/反序列化:把其语言的数据转化成json格式/ 相反
import json v = [12, 3, 4, {'k1': 1}, True, 'adsf'] # 序列化 v = json.dumps(v) # 反序列化 json.loads(v)
# 可转为json的数据中包含中文,让中文彻底显示 v = {'k1': 'alex', 'k2': '你好'} val = json.dumps(v, ensure_ascii=False) print(val, type(val)) val = json.dumps(v) print(val, type(val))
# 使用pickle序列化后,结果是编码后的二进制 import pickle v = {1, 2, 3} val = pickle.dumps(v) print(val, typ(val)) val = pickle.loads(v) print(val, typ(val)) # json dump 获得的是str, pickle获得的是bytes
UTC/GMT:世界协调时间
本地时间:本地时区的时间
# 获取datetime格式时间 from datetime import datetime, timezone, timedelta v1 = datetime.now() v2 = datetime.utcnow() tz = timezone(timedelta(hours = 7)) # 东7区 v3 = datetime.now(tz) # 当前东7区时间 <class 'datetime.datetime'>
# 将datetime格式时间转化为str v1 = datetime.now() v1.strftime('%Y-%m-%d') # 链接不能使用汉字(Mac,linux没问题),可使用.format()方法
# str转datetime,时间加减 val = datetime.strptime('2019-04-18', '%Y-%m-%d') v = val +/- timedelta(days=40) # 当前时间加/减40天
# 时间戳和datetime关系 import time, datetime ctime = time.time() datetime.fromtimestamp(ctime,tz) # 当前时间,tz和上述相同
v = datetime.now() val = v.timestamp() print(val)
做用:根据字符串形式导入模块
开放封闭原则:配置文件开放,代码封闭
# 用字符串形式,去对象中找到其成员 import importlib redis = importlib.import_module('utils.redis') getattr(redis, 'func')()
import importlib path = 'utils.redis.func' module_path, func_name = path.rsplit('.', 1) getattr(module_path, func_name)()
# 导入模块 import importlib middleware_classes = [ 'utils.redis.Redis', 'utils.mysql.MySQL', 'utils.mongo.Mongo' ] for path in middleware_classes: module_path,class_name = path.rsplit('.',maxsplit=1) module_object = importlib.import_module(module_path) # from utils import redis cls = getattr(module_object,class_name) obj = cls() obj.connect() # 用字符串的形式导入模块。 # redis = importlib.import_module('utils.redis') # 用字符串的形式去对象(模块)找到他的成员。 # getattr(redis,'func')()
日志等级(level) | 描述 |
---|---|
DEBUG | 最详细的日志信息,典型应用场景是 问题诊断 |
INFO | 信息详细程度仅次于DEBUG,一般只记录关键节点信息,用于确认一切都是按照咱们预期的那样进行工做 |
WARNING | 当某些不指望的事情发生时记录的信息(如,磁盘可用空间较低),可是此时应用程序仍是正常运行的 |
ERROR | 因为一个更严重的问题致使某些功能不能正常运行时记录的信息 |
CRITICAL | 当发生严重错误,致使应用程序不能继续运行时记录的信息 |
# 方法1, # basicConfig 不能实现中文编码,不能同时向文件和屏幕输出 import logging # logging.Error 默认级别 logging.basicConfig(fielname='cmdb.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s' datefmt = '%Y-%m-%d-%H-%M-%S' level=logging.WARNING) logging.log(10, '日志内容') # 不写 logging.debug('asdfgh') logging.log(30, 'asdfgh') # 写 logging.warning('asdfgh')
应用场景:对于异常处理捕获的内容,使用日志模块将其保存到日志
try: requests.get('http://www.google.com') except Exception as e: msg = str(e) # 调用e.__str__方法 logging.error(msg, exc_info=True) # 线程安全,支持并发
# 方法2 import logging # 对象1:文件 + 格式 file_handler = logging.FileHandler('xxxxx', 'a', encoding='utf-8') fmt = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s') file_handler.setFormatter(fmt) # 对象2:写(封装了对象1 ) logger = logging.Logger('xxx(在log中会显示)', level=logging.ERROR) logger.addHandler(file_handler) logger.error('你好')
# 推荐 import logging file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) logging.error('你好')
logger对像
# warning和error写入不一样文件,须要建立不一样对象 import logging # 须要加入name参数 logger = logging.getLogger() fh = logging.FileHandler('log.log') # 写入文件 sh = logging.StreamHander() # 不须要参数,输出到屏幕 logger.addHander(fh) logger.addHander(sh) # asctime:日志写入时间, name:logger对象名称, levelname:日志级别, module:模块名称 fmt=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s') fh.Setformatter(fmt) logger.waring('message')
import time import logging from logging import handlers # file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, encoding='utf-8') logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) for i in range(1,100000): time.sleep(1) logging.error(str(i)) # 在应用日志时,若是想要保留异常的堆栈信息,exc_info=True msg = str(e) # 调用e.__str__方法 logging.error(msg,exc_info=True)
# dict建立过程 info = dict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
from collections import namedtuple # 可命名tuple(time 结构化时间) # 建立了一个Course类,这个类没有方法,全部属性值不能修改 Course = namedtuple('Course', ['name', 'price', 'teacher']) python = Course('python', 999, 'alex') print(python) print(python.name) print(python.price)
# 把数据转换为四个字节 import struct a = struct.pack('i', 1000) b = struct.pack('i', 78) a1 = struct.unpack('i', a) b1 = struct.unpack('i', b)
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)
优势和应用场景:
# 定义一个类,Account class Account: # 方法, 哪一个对象调用方法,其就是self def login(self,name): print(123) return 666 def logout(self): pass # 调用类中的方法 x = Account() # 实例化(建立)Account类的对象,开辟一块内存 val = x.login('henry') # 使用对象调用class中的方法 print(val)
class File: def read(self): with open(self.path, mode='r', encoding='utf-8') as f: data = f.read() def write(self, content): with open(self.path, mode='a', encoding='utf-8') as f: data = f.write() obj = File() # 建立对象,并使用 obj.path = 'test.txt' # 往obj对象中写入一个私有对象 obj.write(content) # 定义私有属性,私有属性在类外部没法直接进行访问 obj2 = File('info.txt') obj2.write(content)
class Person: # __init__初始化方法(构造方法),给对象内部作初始化 def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender def show(self): temp = 'i am %s, age:%s, gender:%s ' % (self.name, self.age, self.gender) print(temp) # 类(),会执行__init__ obj = Person('henry', 19, 'male') obj.show() obj2 = Person('echo', 19, 'female') obj2.show()
# 类有一个名为 __init__() 的构造方法,该方法在类实例化时会自动调用,通常经过object类进行格式化 # 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
# self.__class__:查看实例所在的类 class Test: def prt(self): print(self) print(self.__class__) t = Test() t.prt()
在类的内部,使用 def 关键字来定义一个方法,与通常函数定义不一样,类方法必须包含参数 self,且为第一个参数,self 表明的是类的实例。self 的名字并非规定死的,也可使用 this,可是最好仍是按照约定是用 self。
类的私有方法**__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods**。
# 循环让用户输入:用户名,密码,邮箱,输入完成后在打印 class Person(): def __init__(self, user, pwd, email): self.username = user self.password = pwd self.email = email def info(self): return temp = 'i am %s, pwd:%s, email:%s ' % (self.username, self.password, self.email,) USER_LIST = [] while 1: user = input('please input user name: ') pwd = input('please input user pwd: ') email = input('please input user email: ') p = Person(user, pwd, email) USER_LIST.append(p) for i in USER_LIST: data = i.info() print(i)
场景:多个类中,若是有公共的方法能够放到基类中,增长代码的重用性。
继承:能够对基类中的方法进行覆写
# 父类(基类) class Base: def f1(self): pass # 单继承,子类,Foo类继承Base类 (派生类) class Foo(Base): def f2(self): pass # 建立了一个子类对象 obj = Foo() # 执行对象.方法时,优先在本身类中找,没有则找其父类 obj.f2() obj.f1() # 建立了一个父类对象 obj = Base() obj.f1() obj.f2() # 会报错
继承关系中的查找方法:
从字面上能够看出一个老一个新,新的必然包含了跟多的功能,也是以后推荐的写法,从写法上区分的话,若是当前类或者父类继承了object类,那么该类即是新式类,不然即是经典类。
class D(object): def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): def bar(self): print 'B.bar' class A(B, C): def bar(self): print 'A.bar' a = A() # 执行bar方法时 # 首先去A类中查找,若是A类中没有,则继续去B类中找,若是B类中么有,则继续去C类中找,若是C类中么有,则继续去D类中找,若是仍是未找到,则报错 # 因此,查找顺序:A --> B --> C --> D # 在上述查找bar方法的过程当中,一旦找到,则寻找过程当即中断,便不会再继续找了 a.bar()
多态:一个类变现出来的多种状态—>多个类表现出类似的状态。
Pyhon不支持Java和C#这一类强类型语言中多态的写法,可是原生多态,Python崇尚“鸭子类型”。list,tuple,python的多态是经过鸭子类型实现的
# 多态,鸭子模型 def func(arg): # 多种类型,不少事物 v = arg[-1] # 必须具备此方法,呱呱叫 print(v)
# 对于一个函数,python对参数类型不会限制,传入参数时能够是各类类型,在函数中若是有例如:arg.append方法,就会对传入类型进行限制。 # 这就是鸭子模型,相似于上述的函数,咱们认为只要能呱呱叫的就是鸭子,只要有append方法,就是咱们想要的类型
Python一样支持运算符重载,咱们能够对类的专有方法进行重载
class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2,10) v2 = Vector(5,-2) print (v1 + v2)
对象成员:实例变量(字段)
Note:属于谁的只容许谁去取,python容许对象去其类中取变量
class Foo: def __init__(self): self.name = 123 def func(self, a, b): print(self.name, a, b) # python内部装饰器 @staticmethod def f(): print(1,2) Foo.f() obj = Foo() obj.func(1, 2) obj.f()
class Foo: def __init__(self): self.name = 123 def func(self, a, b): print(self.name, a, b) # python内部装饰器 @classmethod def f(cls, a, b): print(a, b) Foo.f(1, 2) obj.f(1, 2) # 不推荐
class Foo: @property def func(self): print(123) print(666) obj = Foo() ret = obj.func print(ret)
# 示例:属性 class Page: def __init__(self, total_count, current_page, per_page = 10): self.total_count = total_count self.current_page = current_page self.per_page = per_page @proporty def start_index(self): return(self.current_page -1 ) * self.per_page @property def end_index(self): returno self.current_page * self.per_page_count USER_LIST = [] for i in range(321): USER_LIST.append('henry-%s' % (i,)) # 请实现分页 current_page = int(input('请输入要查看的页码:')) p = Page(321, current_page) data_list = USER_LIST[p.start_index:p.end_index] for i in data_list: print(i)
class Foo: def __init__(self, name): self.__name = name def func(self): print(self.name) obj = Foo('alex') print(obj.__name) # 会报错 obj.func() # 能够访问
class Foo: __x = 1 @staticmethod def func(): print(Foo.__x) obj = Foo() print(Foo.__x) # 会报错 print(obj._Foo__x) # 强制访问私有成员
class School(object): def __init__(self,title): self.title = title def rename(self): pass class Course(object): def __init__(self, name, school_obj): self.name = name self.school = school_obj def reset_price(self): pass class Classes(object): def __init__(self,cname, course_obj): self.cname = cname self.course = course_obj def sk(self): pass s1 = School('北京') c1 = Course('Python', s1) cl1 = Classes('全栈1期', c1)
# 示例1 class StarkConfig(object): pass class AdminSite(object): def __init__(self): self.data_list = [] def register(self, arg): self.data_list.append(arg) site = AdminSite() obj = StarkConfig() site.regisetr(obj)
# 示例2 class StarkConfig(object): def __init__(self, name, age): self.name = name self.age = aeg class AdminSite(object): def __init__(self): self.data_list = [] self.sk = None def set_sk(self, arg=StarkConfig): self.sk =arg site = AdminSite() site.set_sk(StarkConfig) site.sk('henry', 19)
# 示例3 class StarkConfig(object): list_display = 'henry' def changelist(self): print(self.list_display) class UserConfig(StarkConfig): list_display = 'echo' class AdminSite(object): def __init__(self): self._register = {} def registry(self, key, arg=StarkConfig): self._register[key] = arg def run(self): for key, val in self._register.items(): obj = val() obj.changelist() site = AdminSite() site.registry(1) site.registry(2, StackConfig) site.registry(3, UserConfig) # 易错点 echo site.run()
特殊成员:为了可以给快速实现某些方法而生。
# 填充数据,通常称为初始化 class Foo: """ 此类的做用 """ def __init__(self): """ 初始化方法 """ pass
Note
# __new__ 建立一个空对象 # 经过 __init__ 初始化对像 class Foo(object): def __new__(cls, *args, **kwargs): # 在 __init__ 以前 return 'henry'/ object.__new__(cls) obj = Foo() print(obj)
# 对象() 会执行类中的 __call__ 方法 class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('哈哈,你变成我了吧') Foo()() # 第三方模块。写一个网站,用户只要来访问,就自动找到第三个参数并执行 make_server('ip', port, Foo())
obj = dict() obj['k1'] = 123 class Foo(object): def __setitem__(self, key, values): print(key, value) def __getitem__(self, item): return item + 'uuu' def __delitem__(self, key): print(key) obj1 = Foo() obj1['k1'] = 123 # 内部会自动调用__setitem__方法 obj1['xxx'] # 内部会自动调用__getitem__方法 del obj1['ttt'] # 内部会自动调用__delitem__方法
# 只有在打印时,会自动调用此方法,并将返回值显示出来 # type 查看 class Foo: def __str__(self): print('变样是否是不认识我了') return 'henry' obj = Foo() print(obj)
做用: 查看对象中有哪些变量
class Foo(object): def __init__(self, name, age, email): self.name = name self.age = age self.email = email obj = Foo('henry', 19, '123@qq.com') val = obj.__dict__ # 去对象中找到全部变量并将其转换为字典 print(val)
做用:使用with语法时,须要
class Foo(object): def __enter__(self): self.x = open('a.txt', mode='a', encoding='utf-8') return self.x def __exit__(self, exe_type, exc_val, exc_tb): self.x.close() with Foo() as f: # 须要 __enter__ 和 __exit__ 方法 f.write('henry') f.write('echo')
class Foo(object): def __init__(self, v): self.v = v def __add__(self, other): return self.v + other.v obj1 = Foo() obj2 = Foo() val = obj1 + obj2 # obj1触发,把obj1传给self
# 可迭代对象 class Foo: def __iter__(self): return iter([1, 2, 3, 4]) obj = Foo() # 示例2 class Foo: def __iter__(self): yield 1 yield 2 ... obj = Foo()
class Foo(object): pass obj = Foo() print('obj是Foo的对象,开心吧') if type(obj) == Foo else print('哪凉快呆哪去')
# 能够多级继承 class Base(object): pass class Bar(Base): pass class Foo(Bar): pass print(issubclass(Foo, Base))
# 判断某个对象是否时 某个类 或 基类 的实例(对象) class Base(object): pass class Foo(Base): pass obj = Foo() print(isinstance(obj, Foo)) print(isinstance(obj, Base))
# super().func(),根据 self所属类的继承关系进行查找,默认找到第一个就中止 class Bar(object): def func(self): print('bar.func') return 123 class Base(Bar): def func(self): super().func() print('bar.func') return 123 class Foo(Base): def func(self): v = super().func() print('foo.func', v) obj = Foo() obj.func()
# 会打印 hello # 类里的成员会加载,代码会执行 # 函数只有在调用时执行 class Foo(object): print('hello') def func(self): pass
# 类的嵌套 class Foo(object): x = 1 def func(self): pass class Meta(object): y = 123 print('hello') def show(self): print(y.self)
# 可迭代对象示例1 class Foo: def __iter__(self): return iter([1, 2, 3, 4]) obj = Foo() # 示例2 class Foo: def __iter__(self): yield 1 yield 2 ...'' obj = Foo()
# python的约束,易错点 # 约束子类中必需要有send方法,若是没有则会抛出:NotImplementedError class Interface(object): def send(self): raise NotImplementedError() class Foo(Interface): def send(self): pass class Base(Interface): def func(arg): arg.send(arg)
# 应用场景示例 class BaseMassage(object): def send(self): raise NotImplementedError('子类中必须有send方法') class Msg(BaseMassage): def send(self): print('发送短信') class Email(BaseMassage): def send(self): print('发送邮件') class Wechat(BaseMassage): def send(self): print('发送微信') class DingDing(BaseMassage): def send(self): pass obj = Email() obj.send()
反射的概念是由Smith在1982年首次提出的,主要是指程序能够访问、检测和修改它自己状态或行为的一种能力(自省)。这一律念的提出很快引起了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
反射:经过字符串的形式操做对象相关的属性。python中的一切事物都是对象(均可以使用反射)
# getattr示例 class Foo(object): def __init__(self, name): self.name = name obj = Foo('alex') obj.name v1 = getattr(obj, 'name') # setattr示例 obj.name = 'eric' setattr(obj, 'name', 'eric')
# 反射当前文件内容 import sys getattr(sys.modules[__name__], 'ab') # 经过对象获取、示例变量、绑定方法 # 经过类来获取类变量、类方法、静态方法 # 经过模块名获取模块中的任意变量(普通变量、函数、类) # 经过本文件反射任意变量
# 应用示例 class Foo(object): def login(self): pass def regiseter(self): pass obj = Foo() func_name = input('please input method name: ') # 获取方法 getattr(obj, func_name)()
# setattr 示例 class Foo(object): pass obj = Foo() setattr(obj, 'k1', 123) print(obj.k1)
# delattr 示例 class Foo(object): pass obj = Foo() obj.k1 = 999 delattr(obj, 'k1') print(obj.k1)
import x v = x.NUM # 等价于 v = getattr(x, 'NUM') print(v) v = getattr(x, 'func') v() v = getattr(x, 'Foo') val = v() val.x
示例:
# 浏览器两类行为 # way1: 输入地址+回车 get.... # way2: 表单(输入框+按键) post.... # 浏览器都会有get,post,dispatch方法 class View(object): def get(self): pass def Post(self): pass def Dispatch(self): # 请求第一步来这,在进行分发 pass
# 推荐使用性能较好 class Foo(object): def post(self): pass # 方式1 if hasattr(obj, 'get'): getattr(obj, 'get') # 方式2:推荐使用 v = getattr(obj, 'get', None) print(v)
场景:数据库链接和数据库链接池(数据一致时)
设计模式:23种设计模式
class Foo(object): pass # 每实例化一次,就建立一个新对象,内存地址 不同 obj1 = Foo() obj2 = Foo()
# 单例(Singleton)模式,不管是实例化多少次,都用第一次建立的那个对象,内存地址同样 class Singleton(object): instance = None def __new__(cls, *args, **kwargs): if not cls.instance: cls.instance = object.__new__(cls) return cls.instance obj1 = Singleton() # 内存地址一致 obj2 = Singleton()
# 须要加锁,多线程,并发
class FileHelper(object): instance = None def __init__(self, path): self.file_object = open(path, mode='r', encoding='utf-8') def __new__(cls, *args, **kwargs): if not cls.instance: cls.instance = object.__new__(cls) return cls.instance obj1 = FileHelper('x') # 内存地址一致 obj2 = FileHelper('x')
# 导入模块,只是保留模块内存 # 思考角度:函数名不能重复、内存溢出 from jd import n1 # 屡次导入,模块只会加载一次,即便模块中包含其余模块 import jd import jd print(456)
# 屡次导入,模块只会加载一次,即便模块中包含其余模块 import importlib import jd # 手动加载,会覆盖第一次导入 importlib.reload(jd) print(456)
# jd.py class Foo(object): pass obj = Foo()
# app.py import jd # 加载jd.py,加载最后会实例化一个Foo对象并赋值给obj print(jd.obj)
import os import re import datetime import xlrd import requests
# app(程序入口)/src(业务相关)/lib(公共的类库)/db(文件)/config(配置) app.py 越简单越好,少于10行
# app(程序入口)/src(业务相关)/lib(公共的类库)/db(文件)/config(配置) # bin(多个可执行文件例如:student.py,teacher.py,admin.py) # log (存储日志文件) # seetings(BASE_PATH,LOG_FILE_NAME...) path = sys.path.os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(path)
# 若果规则有重叠,须要长的在前面 www.(baidu|google).com # () 表示分组,给一部分正则规定为一组,
1[3-9]\d{9} # 量词前面一个重复次数,9次 1[3-9]\d{9,} # 量词前面一个重复次数,9次以上 1[3-9]\d{n,m} # 量词前面一个重复次数,n-m次 ? # ? 匹配到0次或1次,没匹配上也算一次,匹配上算2次 #(无关紧要,只能有一个) + # + 匹配1次或屡次 * # * 匹配0次或屡次
# 匹配任意小数,保留两位 \d+\.\d{2} # 匹配任意整数或小数 \d+\.?\d* # 有bug \d+(\.\d+)? # 分组实现
\d{7-12} # 默认是贪婪匹配,尽可能多匹配 # 回溯算法 # 非贪婪匹配,惰性匹配,老是匹配符合条件范围内尽可能小的字符串 \d{2,3}? # 匹配两位数 \d+?3 # 尽可能多取,遇到3结束 元字符 量词 ?x # 按照元字符规则在量词范围内匹配,一旦遇到x中止 .*?x # 经常使用,先找x找到匹配结束
# 身份证号匹配(正则表达式,断言) [1-9](\d{16}[\dx]|\d{14}) [1-9]\d{14}(\d{2}[\dx]) ^([1-9]\d{16}[0-9x]|[1-9]\d{14})$
. 是任意字符 * 是取 0 至 无限长度 ? 是非贪婪模式。 .*?x # 就是取前面任意长度的字符,直到一个x出现
# 匹配邮箱 \w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14} # url ^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+
标志 | 含义 |
---|---|
re.S(DOTALL) | 使匹配包括换行在内的全部字符 |
re.I(IGNORECASE) | 使匹配对大小写不敏感 |
re.L(LOCALE) | 作本地化识别(locale-aware)匹配,法语等 |
re.M (MULTILINE) | 多行匹配,影响^和$ |
re.X (VERBOSE) | 该标志经过给予更灵活的格式以便将正则表达式写得更易于理解 |
re.U | 根据Unicode字符集解析字符,这个标志影响\w,\W,\b,\B |
import re tt = "Tina is a good girl, she is cool, clever, and so on..." rr = re.compile(r'\w*oo\w*') print(rr.findall(tt)) # 查找全部包含'oo'的单词 执行结果以下: ['good', 'cool']
格式:re.match(pattern, string, flags=0)
# 从字符串开头匹配,匹配上则返回一个match对像,有group()方法 import re ret = re.match('\d', '8alex83') print(ret)
格式:re.search(pattern, string, flags=0)
print(re.search('\dcom','www.4comrunoob.5com').group()) # 执行结果以下:4com
注:match和search一旦匹配成功,就是一个match object对象,而match object对象有如下方法:
a. group()返回re总体匹配的字符串,
b. group (n,m) 返回组号为n,m所匹配的字符串,若是组号不存在,则返回indexError异常
c.groups()groups() 方法返回一个包含正则表达式中全部小组字符串的元组,从 1 到所含的小组号,一般groups()不须要参数,返回一个元组,元组中的元就是正则表达式中定义的组。
import re a = "123abc456" print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)) #123abc456,返回总体 print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)) #123 print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)) #abc print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)) #456 ###group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分。###
**格式**:re.findall(pattern, string, flags=0)
p = re.compile(r'\d+') print(p.findall('o1n2m3k4')) 执行结果以下: ['1', '2', '3', '4']
import re tt = "Tina is a good girl, she is cool, clever, and so on..." rr = re.compile(r'\w*oo\w*') print(rr.findall(tt)) print(re.findall(r'(\w)*oo(\w)',tt)) # ()表示子表达式 执行结果以下: ['good', 'cool'] [('g', 'd'), ('c', 'l')]
格式:re.finditer(pattern, string, flags=0)
# 匹配到结果为 迭代器,每一项都是match对象,经过group取值 import re ret = re.finditer('\d', 'safh123ghakjdsfg234'*2000000) for i in ret: print(i.group())
**格式**:re.split(pattern, string[, maxsplit],maxsplit用于指定最大分割次数,不指定将所有分割。 - 按照可以匹配的子串将string分割后返回列表。 - 可使用re.split来分割字符串,如:re.split(r'\s+', text);将字符串按空格分割成一个单词列表。 ```python import re ret = re.split('\d+', 'henry18') print(ret) # 保留分组中内容 ret = re.split('(\d+)', 'henry18') print(ret) ```
**格式**:re.sub(pattern, repl, string, count=0) **格式**:subn(pattern, repl, string, count=0, flags=0)
不返回/返回替换次数
import re text = "JGood is a handsome boy, he is cool, clever, and so on..." print(re.sub(r'\s+', lambda m:'['+m.group(0)+']', text,0)) # flags=0默认参数 执行结果以下: JGood[ ]is[ ]a[ ]handsome[ ]boy,[ ]he[ ]is[ ]cool,[ ]clever,[ ]and[ ]so[ ]on...
python # 替换 n 次 ret = re.sub('\d', 'G', 'henry18',n) print(ret) # 返回替换次数(tuple类型) ret = re.subn('\d', 'G', 'henry18') print(ret) # 返回值为tuple类型
```
语法 | 含义 | 示例 | |
---|---|---|---|
(?P
|
分组,除了原有的编号外再指定一个额外的别名 | (?P
|
abcabc |
(?P=name) | 引用别名为
|
(?P
|
1abc15abc5 |
<number> | 引用编号为
|
(\d)abc\1 | 1abc15abc5 |
(?<=….) | 以…开头,并不包括开头 | ||
(?<!….) | 不以…结尾,并不包括开头 |
s = '<h1>wahaha</h1>' ret = re.search('(\w+)>(.*?)</\w+>', s) print(ret.group()) print(ret.group(1)) print(ret.group(2))
ret = re.search('<(?P<tag>\w+)>(?P<content>.*?)</\w+>', s) print(ret.group('tag')) print(ret.group('content'))
s = '<h1>wahaha</h1>' ret = re.search('(?P<tag>\w+)>.*?</(?P=tag)>', s) print(ret.group())
s = '<h1>wahaha</h1>' # \1 在python中有特殊含义 ret = re.search(r'(\w+)>.*?</\1>', s) print(ret.group())
# findall 遇到正则中的分组 优先 显示分组中的内容 import re ret = re.findall('\d(\d)', 'henry18') print(ret) # 取消分组优先(?:正则表达式) ret = re.findall('\d+(?:\.\d+)?', '1.234+2') print(ret)
# 保留分组中内容 ret = re.split('(\d+)', 'henry18') print(ret)
# 示例1:匹配单个数字,findall方法会有屏蔽全部其余匹配项,只显示分组中内容 import re ret = re.findall(r'\d+\.\d+|(\d)', '2+23*3.42/3.2') print(ret) while True: if '' not in ret:break ret.remove('') print(ret)
# 示例2:匹配以...开头的数据,不包括开头 import re m = re.findall('(?<=>)\w+', '\<a>wahaha\</a>\<b>banana\</b>\<h1>qqxing\</h1>') for i in m: print(i) # 匹配不以...开头的数据,不包括结尾 m = re.findall('(?<!>)\w+', '\<a>wahaha\</a>\<b>banana\</b>\<h1>qqxing\</h1>') print(m)
# 示例3:以a开头,由至少一个字母组成的字 ^a[a-zA-Z]+ ^a[a-zA-Z]*
# 以1开头,中间3-5个数字,若是中间位置超过5个数字,则整个字符串不匹配 ^1\d{3,5}$
# 示例4:匹配用户输入的身份证号 import re content = input('用户输入:') ret = re.match('[1-9]\d{14}(\d{2}[\dx])?$', content)
# 示例5:第一个乘除法 import re ret = re.search('\d+(\.\d+)?[\*]-?\d+(\.\d+)?', s)
两个运行中的程序传递信息?
网络应用开发架构
OSI五层协议(简化)
TCP/IP(arp在tcp/ip中属于网络层)
import socket socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None) # 建立socket对象的参数说明:
参数 | 含义 |
---|---|
family | 地址系列应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。 (AF_UNIX 域其实是使用本地 socket 文件来通讯) |
type | 套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或其余SOCK_常量之一。 SOCK_STREAM 是基于TCP的,有保障的(即能保证数据正确传送到对方)面向链接的SOCKET,多用于资料传送。 SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。 |
proto | 协议号一般为零,能够省略,或者在地址族为AF_CAN的状况下,协议应为CAN_RAW或CAN_BCM之一。 |
fileno | 若是指定了fileno,则其余参数将被忽略,致使带有指定文件描述符的套接字返回。 与socket.fromfd()不一样,fileno将返回相同的套接字,而不是重复的。 这可能有助于使用socket.close()关闭一个独立的插座。 |
type = socket.SOCK_STREAM # 表示tcp协议 # server 端 import socket sk = socket.socket() sk.bind(('127.0.0.1'), port号) sk.listen(n) # 监听连接,n 表示容许多少个客户端等待,3.7以后无限制可省略 con,cli_addr = sk.accept() # 接受客户端连接,阻塞,服务端须要一直监听,不能关闭 con.recv(size) # 接收字节数 con.send('content'.encode('utf-8')) # socket 发送接收都是字节流,即二进制 con.close() #关闭客户端套接字 sk.close() #关闭服务器套接字(可选) # client 端 import socket sk = socket.socket() sk.connet(('ip', port号)) sk.send('content'.encode('utf-8')) sk.recv(size) sk.close()
# ip和端口占用解决方法,针对macos import socket from socket import SOL_SOCKET,SO_REUSEADDR # 加入一条socket配置,重用ip和端口 sk = socket.socket() sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 就是它,在bind前加 sk.bind(('127.0.0.1',8898)) # 把地址绑定到套接字
# 自定义协议,解决黏包问题 # server端 import struct import socket sk = socket.socket() sk.bind(('ip', port)) sk.listen() con, cli_addr = sk.accept() size = con.recv(4) size = struct.unpack(size)[0] # unpack,为一tuple类型 content = con.recv(size).decode('utf-8')# 接收文件内容 con.close() sk.close() # client端 import struct import socket sk = socket.socket() sk.connect(('ip', port)) content = '我是henry'.encode('utf-8') # 字节流 size = struct.pack('i', len(content)) # 发送内容长度进行struct sk.send(size) sk.send(content) sk.close()
# server import socket sk = socket.socket(type = socket.SOCK_DGRAM) sk.bind(('127.0.0.1', 9000)) msg, client_addr = sk.recvfrom(1024) print(msg) sk.sendto(b'received', client_addr) sk.close() # client import socket sk = socket.socket(type = socket.SOCK_DGRAM) sk.sendto(b'hello', ('127.0.0.1', 9000)) ret = sk.recv(1024) print(ret) sk.close()
import socket # 服务端套接字函数 s.bind() # 绑定(主机,端口号)到套接字 s.listen() # 开始TCP监听 s.accept() # 被动接受TCP客户的链接,(阻塞式)等待链接的到来 # 客户端套接字函数 s.connect() # 主动初始化TCP服务器链接 s.connect_ex() # connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 # 公共用途的套接字函数 s.recv() # 接收TCP数据 s.send() # 发送TCP数据 s.sendall() # 发送TCP数据 s.recvfrom() # 接收UDP数据 s.sendto() # 发送UDP数据 s.getpeername() # 链接到当前套接字的远端的地址 s.getsockname() # 当前套接字的地址 s.getsockopt() # 返回指定套接字的参数 s.setsockopt() # 设置指定套接字的参数 s.close() # 关闭套接字 # 面向锁的套接字方法 s.setblocking() # 设置套接字的阻塞与非阻塞模式 s.settimeout() # 设置阻塞套接字操做的超时时间 s.gettimeout() # 获得阻塞套接字操做的超时时间 # 面向文件的套接字的函数 s.fileno() # 套接字的文件描述符 s.makefile() # 建立一个与该套接字相关的文件
# 官方文档对socket模块下的socket.send()和socket.sendall()解释以下: socket.send(string[, flags]) Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data. # send()的返回值是发送的字节数量,这个数量值可能小于要发送的string的字节数,也就是说可能没法发送string中全部的数据。若是有错误则会抛出异常。 socket.sendall(string[, flags]) Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from string until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent. # 尝试发送string的全部数据,成功则返回None,失败则抛出异常。 # 故,下面两段代码是等价的: sock.sendall('Hello world\n') buffer = 'Hello world\n' while buffer: bytes = sock.send(buffer) buffer = buffer[bytes:]
# server端 import socket sk = socket.socket() sk.bind(('127.0.0.1', 9000)) sk.setblocking(False) # 设置为非阻塞状态 sk.listen() user = [] del_user = [] while True: try: con, addr = sk.accept() user.append(con) except BlockingIOError: for i in user: try: content = i.recv(1024).decode('utf-8') if not content: del_user.append(i) continue i.send(content.upper(). encode('utf-8')) # 发送的bytes类型能够直接解释出(ascii字符) except BlockingIOError:pass # 注意异常,会报错 for i in del_user: user.remove(i) del_user.clear() sk.close()
# clinet端 import time import socket sk = socket.socket() sk.connect(('127.0.0.1', 9000)) while True: sk.send(b'hello') msg = sk.recv(1024) print(msg) time.sleep(0.2) sk.close()
# 客户端使用对象是用户,直接登录验证 # 能够看到源码,在服务端进行验证登录 # 客户端使用对象是机器
import hmac secret_key = b'asdfgh' random_seq = os.urandom(32) hmac.new(secret_key, random_seq) ret = hmac.digest() # 结果是bytes类型数据
# 使用TCP协议发送数据为空时,默认不会发送 # server端 import os import hmac import socket def chat(con): while True: msg = con.recv(1024).decode('utf-8') print('------>', msg) con.send(msg.upper().encode('utf-8')) # con.send(''.encode('utf-8')) # tcp不会发送 sk = socket.socket() sk.bind(('127.0.0.1', 9000)) sk.listen() com_key = b'henry' while True: con, addr = sk.accept() sec_key = os.urandom(32) con.send(sec_key) # 第一次发送 val = hmac.new(com_key, sec_key).digest() data = con.recv(32) # 第一次接收 if data == val: print('客户端合法') chat(con) else: print('客户端不合法') con.close() sk.close()
# client 端 import socket import hmac def chat(sk): while True: sk.send('hello'.encode('utf-8')) msg = sk.recv(1024).decode('utf-8') print('------>', [msg]) sk = socket.socket() sk.connect(('127.0.0.1', 9000)) sec_key = sk.recv(32) # 第一次接收 com_key = b'henry' val = hmac.new(com_key, sec_key).digest() sk.send(val) # 第一次发送 chat(sk) sk.close()
# 进阶示例 from socket import * import hmac,os secret_key=b'henry bang bang bang' def conn_auth(conn): ''' 认证客户端连接''' print('开始验证新连接的合法性') msg=os.urandom(32) conn.sendall(msg) h=hmac.new(secret_key,msg) digest=h.digest() respone=conn.recv(len(digest)) return hmac.compare_digest(respone,digest) def data_handler(conn,bufsize=1024): if not conn_auth(conn): print('该连接不合法,关闭') conn.close() return print('连接合法,开始通讯') while True: data=conn.recv(bufsize) if not data:break conn.sendall(data.upper()) def server_handler(ip_port,bufsize,backlog=5): '''只处理连接''' tcp_socket_server=socket(AF_INET,SOCK_STREAM) tcp_socket_server.bind(ip_port) tcp_socket_server.listen(backlog) while True: conn,addr=tcp_socket_server.accept() print('新链接[%s:%s]' %(addr[0],addr[1])) data_handler(conn,bufsize) if __name__ == '__main__': ip_port=('127.0.0.1',9999) bufsize=1024 server_handler(ip_port,bufsize)
# 客户端 __author__ = 'Linhaifeng' from socket import * import hmac,os secret_key=b'linhaifeng bang bang bang' def conn_auth(conn): '''验证客户端到服务器的连接''' msg=conn.recv(32) h=hmac.new(secret_key,msg) digest=h.digest() conn.sendall(digest) def client_handler(ip_port,bufsize=1024): tcp_socket_client=socket(AF_INET,SOCK_STREAM) tcp_socket_client.connect(ip_port) conn_auth(tcp_socket_client) while True: data=input('>>: ').strip() if not data:continue # tcp协议不支持发送数据为空 if data.lower() == 'q':break tcp_socket_client.sendall(data.encode('utf-8')) respone=tcp_socket_client.recv(bufsize) print(respone.decode('utf-8')) tcp_socket_client.close() if __name__ == '__main__': ip_port=('127.0.0.1',9999) bufsize=1024 client_handler(ip_port,bufsize)
# server端 import socketserver # socket是socketserver的底层模块和time,datetime同样 class Myserver(socketserver.BaseRequestHandler): def handle(self): # 自动触发handle方法,self.request == con print(self.request) # con server = socketsever.ThreadingTCPServer(('127.0.0.1', 9000), Myserver) server.server_forever() # client import socket sk = socket.socket() sk.connect(('127.0.0.1', 9000))
# 进阶示例 import socketserver class Myserver(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() # self.client_address print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "127.0.0.1", 9999 # 设置allow_reuse_address容许服务器重用地址 socketserver.TCPServer.allow_reuse_address = True # 建立一个server, 将服务地址绑定到127.0.0.1:9999 server = socketserver.TCPServer((HOST, PORT),Myserver) # 让server永远运行下去,除非强制中止程序 server.serve_forever() # client端 import socket HOST, PORT = "127.0.0.1", 9999 data = "hello" # 建立一个socket连接,SOCK_STREAM表明使用TCP协议 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect((HOST, PORT)) # 连接到客户端 sock.sendall(bytes(data + "\n", "utf-8")) # 向服务端发送数据 received = str(sock.recv(1024), "utf-8") # 从服务端接收数据 print("Sent: {}".format(data)) print("Received: {}".format(received))
—>磁带存储+批处理(下降数据的读取时间,提升cpu的利用率)
—>多道操做系统:数据隔离、时空复用(可以遇到I/O操做的时候主动把cpu让出来,给其余任务使用,切换须要时间,由OS完成)
—> 短做业优先算法、先来先服务算法
—>分时OS:时间分片,CPU轮转,每个程序分配一个时间片,下降了cpu利用率,提升了用户体验
—>分时OS + 多道OS:多个程序一块儿执行,遇到IO切换,时间片到了也要切换
Note:遇到io切,占用cpu时间过长也切,核心在于切以前将进程的状态保存下来,这样
才能保证下次切换回来时,能基于上次切走的位置继续运行。
OS做用:将应用程序对硬件资源的竞态请求变得有序化
进程状态:运行(runing) 就绪(ready) 阻塞(blocking)
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是OS结构的基础。
在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
顾名思义,进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。
进程的概念起源于操做系统,是操做系统最核心的概念,也是操做系统提供的最古老也是最重要的抽象概念之一。操做系统的其余全部内容都是围绕进程的概念展开的。
PS:即便能够利用的cpu只有一个(早期的计算机确实如此),也能保证支持(伪)并发的能力。将一个单独的cpu变成多个虚拟的cpu(多道技术:时间多路复用和空间多路复用+硬件上支持隔离),没有进程的抽象,现代计算机将不复存在。
进程概念
特色
# 获取进程的pid, 父进程的id及ppid import os import time print('start') time.sleep(20) print(os.getpid(),os.getppid(),'end')
# 把func函数交给子进程执行 import os import time from multiprocessing import Process def func(): print('start', os.getpid()) time.sleep(1) print('end', os.getpid()) if __name__ == '__main__': p = Process(target=func) # 建立一个即将要执行的进程对象 p.start() # 开启一个进程,异步非阻塞 p.join() # 同步阻塞,直到子进程执行完毕 print('main', os.getpid()) # 异步的程序,调用开启进程的方法,并不等待这个进程的开启
ps:__name__ 只有两种状况,文件名或双下划线main字符串
# windows 经过(模块导入)执行父进程文件中的代码获取父进程中的变量 只要是不但愿被子进程执行的代码,就写在if __name__ == '__mian__'下 进入导入时,父进程文件中的 __name__ != '__mian__' # linux/macos 建立新的子进程是copy父进程内存空间,完成数据导入工做(fork),正常写就能够 公司开发环境都是linux,无需考虑win中的缺陷 # windows中至关于把主进程中的文件又从头执行了一遍 # linux,macos不执行代码,直接执行调用的函数在Windows操做系统中因为没有fork(linux操做系统中建立进程的机制),在建立子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。所以若是将process() 直接写在文件中就会无限递归建立子进程报错。因此必须把建立子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候 ,就不会递归运行了。
# 在多个子进程中使用join方法 from multiprocessing import Process def send_mail(i): print('邮件已发送', i) if __name__ == '__main__': li = [] for i in range(10): p = Process(target=send_mail, args=(i,)) # args必须是元组,给子进程中的函数传参数 p.start() li.append(p) for p in li: p.join() # 阻塞,知道全部子进程执行完毕 print('100封邮件已发送') # 主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,须要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
p.daemon:默认值为False,若是设为True,表明p为后台运行的守护进程,当p的父进程终止时,p也随之终止,而且设定为True后,p不能建立本身的新进程,必须在p.start()以前设置
import time from multiprocessing import Process def son1(): while True: print('is alive') time.sleep(0.5) def son2(): for i in range(5): print('in son2') time.sleep(1) if __name__ == '__main__': p = Process(target=son1) p.daemon = True # 把p子进程设置成了守护进程 p.start() p2 = Process(target=son2) p2.start() time.sleep(2) # 守护进程是随着主进程‘代码’结束而结束 # 全部子进程都必须在主进程结束以前结束 # 守护进程内没法再开启子进程,不然抛出异常:AssertionError: daemonic processes are not allowed to have children
import time from multiprocessing import Process def son1(): while True: print('is alive') time.sleep(0.5) if __name__ == '__main__': p = Process(target=son1) p.start() # 开启了一个进程 print(p.is_alive) # 判断子进程时候存活, True和False time.sleep(1) p.terminate() # “异步非阻塞”,强制结束一个子进程 print(p.is_alive) # True,os还没来得及关闭进程 time.sleep(0.01) print(p.is_alive) # False,OS已经响应了关闭进程的需求,再去检测的时候,结果是进程已经结束
import os import time from multiprocessing import Process class MyProcess(Process): def __init__(self, x, y): # 子进程若是不须要参数,能够省略 self.x = x self.y = y super().__init__() def run(self): while True: print(self.x, self.y, os.getpid()) print('in myprocess') if __name__ == '__main__': mp = MyProcess(1, 2) mp.daemon = True mp.start() # 开启一个子进程,会调用run()方法 time.sleep(1) mp.terminate() # 结束进程,异步非阻塞 print(mp.is_alive()) # True time.sleep(0.01) print(mp.is_alive()) # False
# 数据操做时,不能同时进行修改 import json from multiprocessing import Process, Lock # 导入Lock def search_ticket(user): with open('tickets.txt') as f: dic = json.load(f) print('%s查询结果:%s张余票' %(user, dic['count'])) def buy_ticket(user, lock): # with lock: lock.acquire() # time.sleep(0.01) with open('tickets.txt') as f: dic = json.load(f) if dic["count"] > 0: print('%s已买到票' % user) dic["count"] -= 1 else: print('%s没买到票' % user) with open('tickets.txt', 'w') as f: json.dump(dic, f) lock.release() if __name__ == '__main__': lock = Lock() # 实例化一个对象 for i in range(10): search_ticket('user%s '%(i+1),) p = Process(target=buy_ticket, args=('user%s '%(i+1), lock)) p.start()
from multiprocessing import Process n = 100 def func(): global n n -= 1 li = [] for i in range(10): p = Process(target=func) p.start() li.append(p) for p in li:p.join() print(n)
from multiprocessing import Process,Queue def func(exp,q): res = eval(exp) q.put(res) if __name__ == '__main__': q = Queue() p = Process(target=func, args=('1+2+3',q)) p.start() print(q.get())
from multiprocessing import Pipe pip = Pipe() pip.send() pip.recv()
# Process中的队列 import queue from multiprocessing import Queue q = Queue(3) # 可设置队列长度 q.put(1) q.put(2) # 对列为满时,继续放数据会发生阻塞 q.put(3) print('----------') try: q.put_nowait(4) # 对列为满时,继续放数据会报错和丢失 except queue.Full:pass print('----------') q.get() q.get() q.get() # 对列为空时,会发生阻塞 try: q.get_nowait() # 对列为空时,会报错,阻塞会取消 except queue.Empty:pass
q.empty() # 有缺陷 q.qsize() q.full()
# 生产者消费者模型示例 import time import random from multiprocessing import Process, Queue def producer(q, name, food): for i in range(10): time.sleep(random.random()) fd = '%s%s' % (food, i) q.put(fd) print('%s生产了一个%s' % (name, food)) def consumer(q, name): while True: food = q.get() if not food: q.put(None) break time.sleep(random.randint(1, 3)) print('%s吃了%s' % (name, food)) def cp(num1, num2): q = Queue(10) p_l = [] for i in range(num1): p = Process(target=producer, args=(q, 'henry', 'food')) p.start() p_l.append(p) for i in range(num2): c = Process(target=consumer, args=(q, 'echo%s' % (i+1,))) c.start() for i in p_l: i.join() q.put(None) if __name__ == '__main__': cp(1, 4)
# 生产者消费者模型示例之爬虫 import re import requests from multiprocessing import Process, Queue def producer(q, url): response = requests.get(url) q.put(response.text) def consumer(q): while True: s = q.get() if not s: q.put(None) break com = re.compile( '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>' '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S) ret = com.finditer(s) for i in ret: print({ "id": i.group("id"), "title": i.group("title"), "rating_num": i.group("rating_num"), "comment_num": i.group("comment_num"), }) if __name__ == '__main__': count = 0 q = Queue() p_l = [] for i in range(10): count += 25 p = Process(target=producer, args=(q, 'https://movie.douban.com/top250?start=%s&filter=' % count)) p.start() p_l.append(p) for i in range(5): c = Process(target=consumer, args=(q,)) c.start() for i in p_l: i.join() q.put(None)
# joinable实现生产者、消费者模型 import time import random from multiprocessing import Process,JoinableQueue def producer(q, name, food): for i in range(10): time.sleep(random.random()) fd = '%s%s'%(food,i) print('%s生产了一个%s'%(name, food)) q.join() def consumer(q, name, food): while True: food = q.get() if not food: q.put(None) break time.sleep(random.randint(1, 3)) print('%s吃了%s'%(name, food)) q.task_done() if __name__ = '__main__': jq = JoinableQueue() p = Processor(target=producer, args=(jq, 'henry', 'food')) p.start()
# 进程间数据是独立的,能够借助于队列或管道实现通讯,两者都是基于消息传递的 # 虽然进程间数据独立,但能够经过Manager实现数据共享,事实上Manager的功能远不止于此 A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies. A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array.
from mutliprocessing import Manager,Lock def func(dic, lock): with lock: dic['count'] -= 1 if __name__ = '__main__': # m = Manager() lock = Lock() with Manager() as m: l = Lock() dic = m.dict({'count': 100}) # 共享的dict,list li = m.list([1,2,3]) p_l = [] for i in range(100): p = Process(target=func, args=(dic,lock)) p.start() p_l.append(p) for p in p_l:p.join() print(dic)
GIL(global interpreter lock):全局解释器锁
# multiprocessing 是彻底仿照Threading类的 import os import time from threading imoprt Thread def func(): print('start son thread') time.sleep(1) print('end son thread', os.getpid()) Thread(target=func).start() # 开启一个线程的速度很是快 print('start') time.sleep(0.5) print('end', os.getpid())
# 开启多个线程 import os import time from threading imoprt Thread def func(): print('start son thread') time.sleep(1) print('end son thread', os.getpid()) for i in range(10): Thread(target=func).start() # 开启一个线程的速度很是快 # 线程的调度由OS决定
import os import time from threading imoprt Thread def func(): print('start son thread') time.sleep(1) print('end son thread', os.getpid()) t_l = [] for i in range(10): t = Thread(target=func) t.start() t_l.append(t) for i in t_l:i.join() print('子线程执行结束')
from threading import Thread class MyThread(Thread): def __init__(self, i): self.i = i super().__init__() # 注意变量名避免与父类init中的变量重名 def run(self): print(self.i, self.ident) # 经过self.ident,查看子线程的id t_l = [] for i in range(100): t = MyThread(i) t_l.append(t) t.start() # start 方法封装了开启线程的方法和run方法 for t in t_l: t.join() print('主进程结束')
from threading import current_thread, enumerate, active_count def func(): print('start son thread', i , current_thread()) time.sleep(1) print('end son thread', os.getpid()) t = Thread(target=func) t.start() print(t.ident) print(current_thread().ident) # current_ident()在哪一个线程,就获得这个线程id print(enumerate()) # 统计当前进程中多少线程活着,包含主线程 print(active_count()) # 统计当前进程中多少线程活着,个数,包含主线程 # 线程中不能从主线程结束一个子线程 current_thread().name # 当前线程名称 current_thread().ident # 当前线程id current_thread().isalive() # 当前线程是否存活 current_thread().isdaemon() # 当前线程是不是守护线程
import time from threading import Thread from multiprocessing import Process def func(a, b): c = a + b if __name__ == '__main__': p_l = [] start = time.time() for i in range(100): p = Process(target=func, args=(i, i*2)) p.start() p_l.append(p) for i in P_l:i.join() print(time.time() - start) t_l = [] start = time.time() for i in range(100): t = Thread(target=func, args=(i, i*2)) t.start() t_l.append(t) for i in t_l:i.join() print(time.time() - start)
# 不要在子线程里随便修改全局变量 from threading import Thread n = 100 def son(): global n n -= 1 t_l = [] for i in range(100): t = Thread(target=son) t_l.append(t) t.start() for t in t_l:t.join() print(n)
import time from threading imoprt Thread def son(): while True: time.sleep(0.5) def son2(): for i in range(5): t = Thread(target=son) t.daemon = True t.start() time.sleep(3)
# 线程数据一样不安全 import dis a = 0 def func(): global a a += 1 dis.dis(func) # 返回cpu指令
# 使用互斥锁解决线程全局变量数据不安全问题 from threading import Thread, Lock a = 0 def add_f(lock): global a with lock: for i in range(2000000): a += 1 def sub_f(lock): global a with lock: for i in range(2000000): a -= 1 lock = Lock() t1 = Thread(target=add_f, args=(lock,)) t1.start() t2 = Thread(target=sub_f, args=(lock,)) t2.start() t1.join() t2.join() print(a)
互斥锁:是锁中的一种,在同一线程中,不能连续lock.acquire()屡次
from threading import Lock lock = Lock() lock.acquire() print('-------------') lock.acquite() print('-------------')
import time import random from threading import Thread class Singleton: from threading import Lock # 复用性考虑 __instance = None lock = Lock() def __new__(cls, *args, **kwargs): with cls.lock: if not cls.__instance: time.sleep(random.random()) # 切换GIL锁 cls.__instance = super().__new__(cls) return cls.__instance def fun(): print(Singleton()) li = [] for i in range(10): t = Thread(target=fun) li.append(t) t.start() for t in li: t.join()
from threading import Thread,Lock noodle_lock = Lock() fork_lock = Lock() def eat1(name,noddle_lock, fork_lock): noddle_lock.acquire() print('%s抢到面了'%name) fork_lock.acquire() print('%s抢到叉子了'%name) print('%s吃了一口面'%name) noddle_lock.release() print('%s放下面了'%name) fork_lock.release() print('%s放下叉子了'%name) def eat2(name,noddle_lock, fork_lock): fork_lock.acquire() print('%s抢到叉子了'%name) noddle_lock.acquire() print('%s抢到面了'%name) print('%s吃了一口面'%name) noddle_lock.release() print('%s放下面了'%name) fork_lock.release() print('%s放下叉子了'%name)
import time from threading import RLock, Thread noodle_lock = fork_lock = RLock() # 将多把互斥锁变成了一把递归锁 def eat1(name, noodle_lock, fork_lock): noodle_lock.acquire() print('%s抢到面了' % name) fork_lock.acquire() print('%s抢到叉子了' % name) print('%s吃了一口面' % name) time.sleep(0.1) fork_lock.release() print('%s放下叉子了' % name) noodle_lock.release() print('%s放下面了' % name) def eat2(name, noodle_lock, fork_lock): fork_lock.acquire() print('%s抢到叉子了' % name) noodle_lock.acquire() print('%s抢到面了' % name) print('%s吃了一口面' % name) time.sleep(0.1) noodle_lock.release() print('%s放下面了' % name) fork_lock.release() print('%s放下叉子了' % name) lst = ['henry', 'echo', 'dean', 'daniel'] Thread(target=eat1, args=(lst[0], noodle_lock, fork_lock)).start() Thread(target=eat2, args=(lst[1], noodle_lock, fork_lock)).start() Thread(target=eat1, args=(lst[2], noodle_lock, fork_lock)).start() Thread(target=eat2, args=(lst[3], noodle_lock, fork_lock)).start()
# 使用互斥锁解决问题 import time from threading import Lock, Thread lock = Lock() def eat1(name, lock): lock.acquire() print('%s抢到面了' % name) print('%s抢到叉子了' % name) print('%s吃了一口面' % name) time.sleep(0.1) print('%s放下叉子了' % name) print('%s放下面了' % name) lock.release() def eat2(name, lock): lock.acquire() print('%s抢到叉子了' % name) print('%s抢到面了' % name) print('%s吃了一口面' % name) time.sleep(0.1) print('%s放下面了' % name) print('%s放下叉子了' % name) lock.release() lst = ['henry', 'echo', 'dean', 'daniel] Thread(target=eat1, args=(lst[0], lock)).start() Thread(target=eat2, args=(lst[1], lock)).start() Thread(target=eat1, args=(lst[2], lock)).start() Thread(target=eat2, args=(lst[3], lock)).start()
import queue # 先进先出队列:服务 from queue import Queue q = Queue(5) q.put(1) q.get() # 后进先出队列:算法 from queue import LifoQueue lfq = LifiQueue(4) lfq.put(1) lfq.put(2) lfq.get() lfq.get() # 优先级队列:自动排序、vip用户、告警级别 from queue import PriorityQueue pq = PriorityQueue() pq.put((10, 'henry')) pq.put((6, 'echo')) pq.put((10, 'dean')) pq.get() pq.get() pq.get()
# 进程池。 p.submit, p.shutdown import os,time, random from concurrent.futrures import ProcessPoolExecutor def func(i): print('start', os.getpid()) time.sleep(random.randint(1,3)) print('end', os.getpid()) return '%s * %s' %(i, os.getpid()) if __name__ == '__main__': p = ProcessPoolExecutor(5) # cpu核心数或多一 ret_l = [] for i in range(10): ret = p.submit(func, i) # 提交进程,参数直接放在其后 ret_l.append(ret) # ret为future对象,ret.result()取值 # 关闭池,不能提交任务,阻塞,直到已经提交的任务执行完毕 p.shutdown() for ret in ret_l: # 会阻塞,至关于q.get() print('------>',ret.result()) # result,同步阻塞 print('main', os.getpid())
# 线程池。p.submit(), p.shutdown(), ret.result() from concurrent.futures import ThreadPoolExecutor def func(i): print('start', os.getpid()) time.sleep(random.randint(1,3)) print('end', os.getpid()) return '%s * %s' %(i, os.getpid()) tp = ThreadPoolExecutor(20) # 线程个数通常为cpu核心数4-5倍 ret_l = [] for i in range(100): ret = tp.submit(func, 1) ret_l.append(ret) for ret in ret_l: print('------->', ret.result()) p.shutdown() print('main')
# 线程池。p.submit(), p.shutdown(), ret.result() from concurrent.futures import ThreadPoolExecutor def func(i): print('start', os.getpid()) time.sleep(random.randint(1,3)) print('end', os.getpid()) return '%s * %s' %(i, os.getpid()) tp = ThreadPoolExecutor(20) # 线程个数通常为cpu核心数4-5倍 ret = tp.map(func, range(20)) # tp.map()方法 for i in ret:print(i) # ret 为生成器对象
from concurrent.futures import ThreadPoolExecutor def get_page(url): content = requests.get(url) return {'url':url, 'content':content.text} def parserpage(dic): print(dic.result()['url']) for url in url_l: ret = get_page(url) ret.add_done_callback(parserpage) # 先执行完,先调用parserpage函数 # ret=add_done_callback(函数名)
from concurrent.futures import ProcessPoolExecutor import requests import os def get_page(url): print('<进程%s> get %s' % (os.getpid(), url)) respone = requests.get(url) if respone.status_code == 200: return {'url': url, 'text': respone.text} def parse_page(res): res = res.result() print('<进程%s> parse %s' % (os.getpid(), res['url'])) parse_res = 'url:<%s> size:[%s]\n' % (res['url'], len(res['text'])) with open('db.txt', 'a') as f: f.write(parse_res) if __name__ == '__main__': urls = ['https://www.baidu.com', 'https://www.openstack.org', 'http://www.sina.com.cn/', 'https://www.tencent.com'] p = ProcessPoolExecutor(3) for url in urls: p.submit(get_page, url).add_done_callback(parse_page) # parse_page拿到的是一个future对象obj,须要用obj.result()拿到结果
协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。一句话说明什么是协程:协程是一种用户态的轻量级线程,即协程是由用户程序本身控制调度的,多个任务在一条线程上来回切换。
协程:用户级别,本身写的py代码;控制切换是OS不可见的
在Cpython解释器:协程和线程都不能利用多核
线程和协程对比
协程特色
对比OS控制线程的切换,用户在单线程内控制协程的切换
优势以下:
缺点以下:
# 切换,协程任务 def func1(): 1 + 2 2 + 3 yield 1 sleep(1) def func2(): g = func1() next(g) next(g)
# 完成切换 import time from greenlet import greenlet def func1(): print(123) time.sleep(0.5) g2.switch() print(123) def func2(): print(456) time.sleep(0.5) print(456) g1.switch() g1 = greenlet(func1) g2 = greenlet(func2) g1.switch()
def sleep(num): t = num + time.time() yield t print('sleep 结束') g1 = sleep(1) g2 = sleep(2) t1 = next(g1) t2 = next(g2) lst = [t1, t2] min_t = min(lst) time.sleep(min_t - time.time()) g1.next() min_t = min(lst) time.sleep(min_t - time.time()) g2.next()
# gevent不认识time.sleep import time import gevent from gevent import monkey monkey.patch_all() # 可能的阻塞方法 def func1(): print(123) gevent.sleep(1) print(123) def func2(): print(456) gevnet.sleep(1) print(456) g1 = gevent.spawn(fun1) g2 = gevent.spawn(fun2) # gevent.sleep(2) # 遇到阻塞才会切换 # g1.join() # 阻塞直到g1任务完成为止 # g2.join() gevent.joinall([g1, g2]) g_l = [] for i in range(10): g = gevent.spawn(func1) g_l.append(g) gevent.joinall(g_l)
# 示例大变身 import gevent from gevent import monkey,time monkey.patch_all() # 对io操做进行重现实现 def func1(): print(123) time.sleep(3) print(456) def func2(): print('---------') time.sleep(1) print('=========') g1 = gevent.spawn(func1) g2 = gevent.spawn(func2) gevent.joinall([g1, g2]) # 阻塞列表中的全部协程 print('main')
print(g1.value ) # value是属性,若是没有执行则为None
import socket import gevent from gevent import monkey monkey.patch_all() sk = socket.socket() sk.bind(('127.0.0.1', 9000)) sk.listen() def chat(con): while True: msg = con.recv(1024).decode('utf-8') con.send(msg.upper().encode('utf-8')) while True: con, _ = sk.accept() gevent.spawn(chat, con)
import asyncio # 只识别自身的方法 # 起一个任务 async def demo(): # 必需要async修饰,协程方法 print('start') await asyncio.sleep(1) # 阻塞,await关键字 + 协程函数 print('end') loop = asyncio.get_event_loop() # 建立一个事件循环 loop.run_until_complete(demo()) # 阻塞,直到协程执行完毕 # 把demo任务丢到事件循环中执行
import asyncio # 只识别自身的方法 async def demo(): # 必需要async修饰,协程方法 print('start') await asyncio.sleep(1) # 阻塞,await关键字 + 协程函数 print('end') loop = asyncio.get_event_loop() # 建立一个事件循环 wait_obj = asyncio.wait([demo(), demo(), demo()]) loop.run_until_complete(wait_obj) # 没有返回值
# 同步取返回值 import asyncio async def demo(): print('start') await asyncio.sleep(1) print('end') return 123 loop = asyncio.get_event_loop() # 建立一个事件循环 t1 = loop.create_task(demo()) t2 = loop.create_task(demo()) tasks = [t1, t2] # 任务列表 wait_obj = asyncio.wait([t1, t2]) loop.run_until_complete(wait_obj) for task in tasks: print(t.result()) # 获取返回值
import asyncio async def demo(i): print('start') await asyncio.sleep(10-i) print('end') return i, 123 async def main(): task_l = [] for i in range(10): task = asyncio.ensure_future(demo(i)) task_l.append(task) for ret in asyncio.as_compeleted(task_l): res = await ret print(res) loop = asyncio.get_event_loop() loop.run_until_compeleted(main())