标签:extend href port producer 主机 易错点 网页 oob 非阻塞io
目录
计算机的主要组成部分时主板、CPU、硬盘、内存及一些外设设备组成。
? 操作系统(OS),是最接近物理硬件的系统软件。主要用来协调、控制、分配计算机硬件资源,使计算机各组件可以发挥最优性能。
? 软件是运行于操作系统之上的应用程序。
? 计算机语言主要是有解释器/编译器/虚拟机,再加上语法规则构成用来开发其他软件的工具。解释型语言,通常是由解释器边解释边执行的计算机语言,例如:python、ruby、PHP、perl。编译型语言,通常是由编译器编译整个代码文件,生成计算机可以识别的文件,交由计算机处理。
? 首先,在官网下载py2与py3,2,3版本有很多不兼容所有会存在两个版本共存的问题。目前,mac、ubuntu等一些系统已经内置了python2版本。
? 为了开发需要,我们需要下载并安装python3。用于开发的软件,通常安装版本一般是找次新版本进行安装。安装pycharm IDE 开发工具。
? 环境变量的功能,及其配置。环境变量分为,用户环境变量(只对当前用户生效)和系统环境变量(所有用户均有效)。主要用于终端使用,不需要输入python解释器的完整路径,只要输入pythonx 就可使用。
? PATH:方便用户在终端执行程序。即,将可执行程序所在的目录添加到环境变量,以后直接调用即可。
? mac的环境变量在~/.bash_profile文件中。通常在安装的时候python会自动生成环境变量,无需手动配置。
? 当前,比较通用的编码有ASCII、Unicode、UTF-8、GB2312、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"
in # 如果在指定的序列中找到值返回 True,否则返回 False
not in # 如果在指定的序列中找到值返回 False,否则返回 True
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)) # 下划线连接个字符
# 返回第一个 a 的索引值,没有则返回 -1
s = 'aaasdfgsh'
index = s.find('a')
print(index)
# 返回第一个 a 的索引值,没有报错
s = 'aaasdfgsh'
index = s.find('a')
print(index)
# 返回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 | — | — | ? | ? | ? | ? | ? |
修改 | — | — | — | ? | — | ? | ? |
删除 | — | — | — | ? | — | ? | ? |
? 所有的容器类例如:list,tuple, dict,set 都可以嵌套,但set(), 只能嵌套可hash(int, bool, str, tuple 4种)的数据类型。
小数据池
缓存规则:
? 文件操作主要用来读取、修改、和创建指定文件。
f = open('文件路径',mode='r/w/a...',encoding='utf-8') # 不写会默认
# mode= 'w'
# 打开文件时,会先清空历史文件,没有则创建
f.write('a')
# mode= 'r'
# way1 整个文件直接读取到RAM
f.read()
f.read(1) # 如果指定编码格式,会读出 1 个字符
# 如果是 mode= rb 会读出 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 = emial
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) # 判断子进程时候存活, Ture和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)
标签:extend href port producer 主机 易错点 网页 oob 非阻塞io
原文地址:https://www.cnblogs.com/henryw/p/10987095.html