一、数据类型
Python3 教程 | 菜鸟教程 (runoob.com)
二、基本函数
1、while和for后面并列一个else表示当循环条件不满足时执行该语句。
2、pass 语句表示只占位置不做任何操作
3、迭代器
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器;通过两种方法的使用或for的方式遍历迭代器里面的数据:
触发 StopIteration 异常来结束迭代:
4、生成器:其实就是返回一个迭代器。
使用了 yield 的函数被称为生成器(generator)。
5、函数
(1)、不带表达式的return相当于返回 None。
(2)、参数传递
在 python 中,类型属于对象,变量是没有类型的:
a=[1,2,3]
a=“Runoob”
等号左边是变量,没有类型;等号右边是对象,有类型。变量仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。
可更改(mutable)与不可更改(immutable)对象
在 python 中,strings,numbers , tuples是不可更改的对象,而 list,dict 等则是可以修改的对象。
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
不可变类型:类似 c++ 的值传递 ,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的对象传过去,修改后fun外部的la也会受影响
(3)、不定长参数
6、匿名函数
lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
7、闭包(直白的说,闭包就是对内部函数的引用)
我们可以将闭包理解为一种特殊的函数,这种函数由两个函数的嵌套组成,且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。
8、变量作用域
好啦,图书馆快打烊了。今天就到这里。
三、面向对象
类与继承
类
#!/usr/bin/python3
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
# 实例化类
p = people('runoob',10,30)
p.speak()
执行以上程序输出结果为:
runoob 说: 我 10 岁。
类的单继承
#!/usr/bin/python3
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
#单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
s = student('ken',10,60,3)
s.speak()
执行以上程序输出结果为:
ken 说: 我 10 岁了,我在读 3 年级
类的多继承
#!/usr/bin/python3
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
#另一个类
class speaker():
topic = ''
name = ''
def __init__(self,n,t):
self.name = n
self.topic = t
def speak(self):
print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
#多重继承
class sample(speaker,student):
a =''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)
test = sample("Tim",25,80,4,"Python")
test.speak() #方法名同,默认调用的是在括号中排前地父类的方法
执行以上程序输出结果为:
我叫 Tim,我是一个演说家,我演讲的主题是 Python
类的属性与方法
类的方法
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self。
类的私有方法
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。
类的私有属性
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
类的专有方法
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较
__call__: 函数调用
__add__: 加
__sub__: 减
__mul__: 乘
__truediv__: 除
__mod__: 求余
__pow__: 乘方
方法的重写(复写)
#!/usr/bin/python3
class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
# super() 函数是用于调用父类(超类)的一个方法。
# 执行以上程序输出结果为:
调用子类方法
调用父类方法
在Pycharm中使用类
导包
调用另一个类的方法
四、正则
基础
1、点号“ . ”
一个点表示除了换行符(\n)以外的任意一个字符。
2、星号“ * ”
一个星号表示他前面的一个表达式的0次到无限次。
3、问号“ ?”
一个问号表示英文问号表示他前面的一个表达式的0次或1次。
4、(.*?)和(.*)的区别
只要是a开头y结尾,切断当第一个元素,继续找a开头y结尾的字符串。
a开头遇到第一个y结尾的并没有立即切断,而是继续找下一个y,直到最后一个y时才切断。
将上面两个表达式括起来表示不要括号外面的数据,只返回括号里边的数据。
5、反斜杠“ \ ”
转义,将特殊含义的字符转成普通字符;将普通字符转为特殊字符。
如:我的密码是*123456*不包括星号。
上面的这么写:我的密码是*.**不包括星号。// 错误
上面的这么写:我的密码是\*.*\*不包括星号。// 将斜杠放在字符前面就不具有特殊含义了
\\n :此时失去了换行的特殊含义。
6、数字“ \d ”
一个\d表示一个数字,以此类推。
如:我的密码是*123456*不包括星号。
我的密码是\*\d*\*不包括星号。 // \d是个整体表示一个数字,紧跟着结合后面的*表示匹配0到无限多个数字。
7、小括号“ () ”
表示把括号里的内容提取出来。
如:我的密码是:123456abcde你帮我记住。
:.*?你 结果是 :123456abcde你 // 不满足需求
:(.*?)你 结果是 123456abcde // 成立
8、其他符号
实例
高级
1、re.match(正则式, 字符串, 修饰符)
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
修饰符:
#!/usr/bin/python3
import re
line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print ("matchObj.group() : ", matchObj.group(0))
print ("matchObj.group(1) : ", matchObj.group(1))
print ("matchObj.group(2) : ", matchObj.group(2))
else:
print ("No match!!")
以上实例执行结果如下:
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
2、re.search(正则式, 字符串, 修饰符)
从头到尾匹配成功re.search方法返回一个匹配的对象,否则返回None。
group(index) // 返回对应下标的值
groups() // 返回所有值
import re
line = "Cats are smarter than dogs";
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print ("searchObj.group() : ", searchObj.group())
print ("searchObj.group(1) : ", searchObj.group(1))
print ("searchObj.group(2) : ", searchObj.group(2))
else:
print ("Nothing found!!")
以上实例执行结果如下:
searchObj.group() : Cats are smarter than dogs // 返回的是整个匹配串
searchObj.group(1) : Cats // 返回的是子串之一
searchObj.group(2) : smarter // 返回的是子串之二
3、re.match()与re.search()区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
import re
line = "Cats are smarter than dogs";
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
print ("match --> matchObj.group() : ", matchObj.group())
else:
print ("No match!!")
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
print ("search --> matchObj.group() : ", matchObj.group())
else:
print ("No match!!")
以上实例运行结果如下:
No match!!
search --> matchObj.group() : dogs
4、re.sub(pattern, repl, string, count=0, flags=0)
Python 的re模块提供了re.sub用于替换字符串中的匹配项。
参数:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags : 编译时用的匹配模式,数字形式。
前三个为必选参数,后两个为可选参数。
import re
phone = "2004-959-559 # 这是一个电话号码"
# 删除注释
num = re.sub(r'#.*$', "", phone)
print ("电话号码 : ", num)
# 移除非数字的内容
num = re.sub(r'\D', "", phone)
print ("电话号码 : ", num)
以上实例执行结果如下:
电话号码 : 2004-959-559
电话号码 : 2004959559
repl 参数是一个函数
以下实例中将字符串中的匹配的数字乘于 2:
import re
# 将匹配的数字乘于 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
执行输出结果为:
A46G8HFD1134
5、compile(pattern[, flags])
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
>>>import re
>>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字
>>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
>>> print m # 返回一个 Match 对象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0) # 可省略 0
'12'
>>> m.start(0) # 可省略 0
3
>>> m.end(0) # 可省略 0
5
>>> m.span(0) # 可省略 0
(3, 5)
6、findall
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。
语法格式为:
findall(string[, pos[, endpos]])
参数:
- string 待匹配的字符串。
- pos 可选参数,指定字符串的起始位置,默认为 0。
- endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
查找字符串中的所有数字:
import re
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)
print(result1)
print(result2)
输出结果:
['123', '456']
['88', '12']
7、re.finditer
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
re.finditer(pattern, string, flags=0)
参数
import re
it = re.finditer(r"\d+","12a32bc43jf3")
for match in it:
print (match.group() )
输出结果:
12
32
43
3
8、re.split
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:
re.split(pattern, string[, maxsplit=0, flags=0])
参数
>>>import re
>>> re.split('\W+', 'runoob, runoob, runoob.')
['runoob', 'runoob', 'runoob', '']
>>> re.split('(\W+)', ' runoob, runoob, runoob.')
['', ' ', 'runoob', ', ', 'runoob', ', ', 'runoob', '.', '']
>>> re.split('\W+', ' runoob, runoob, runoob.', 1)
['', 'runoob, runoob, runoob.']
>>> re.split('a*', 'hello world') # 对于一个找不到匹配的字符串而言,split 不会对其作出分割
['hello world']
五、进程线程协程
进程:表示一个程序的上下文执行活动(打开、执行、保存...)。
线程:进程执行程序的最小调度单位(执行a,执行b...)。
协程:一个线程中会有很多函数,执行某个函数后等待,去执行另一个函数,最后又回来执行之前那个函数,这个过程叫协程。
进程和线程,都是一种CPU的执行单元。
线程由操作系统调度,协程由程序调度。
进程里的各个线程共享进程数据,但是不同进程的线程间不能共享数据。
优点
- 无需线程上下文切换的开销
- 无需锁定及同步的开销
- 方便切换控制流,简化编程模型
- 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
缺点
- 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上。当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
- 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
创建进程
如果并发任务是CPU密集型,多进程效率高
from multiprocessing import Process
from threading import Thread
import os,time
def work():
res=0
for i in range(100000000):
res*=i
if __name__ == '__main__':
l=[]
cpu = os.cpu_count()
print(os.cpu_count()) #本机为4核
start=time.time()
for i in range(cpu):
p=Process(target=work) #进程耗时5s多
p=Thread(target=work) #线程耗时18s多
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start))
创建线程
如果并发任务是I/O密集型,多线程效率高
from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
time.sleep(2)
print('===>')
if __name__ == '__main__':
l=[]
print(os.cpu_count()) #本机为4核
start=time.time()
for i in range(400):
# p=Process(target=work) #进程耗时12s多,大部分时间耗费在创建进程上
p=Thread(target=work) #线程耗时2s多
l.append(p)
p.start()
for p in l:
p.join()
stop=time.time()
print('run time is %s' %(stop-start))
创建协程
1、yield实现协程效果
def consumer(name):
print('开始吃包子...')
while True:
print('\033[31;1m[consumer]%s需要包子\033[0m'%name)
bone = yield #接收send发送的数据
print('\033[31;1m[%s]吃了%s个包子\033[0m'%(name,bone))
def producer(obj1):
obj1.send(None) #必须先发送None
for i in range(3):
print('\033[32;1m[producer]\033[0m正在做%s个包子'%i)
obj1.send(i)
if __name__ == '__main__':
con1 = consumer('消费者A') #创建消费者对象
producer(con1)
#output:
开始吃包子...
[consumer]消费者A需要包子
[producer]正在做0个包子
[消费者A]吃了0个包子
[consumer]消费者A需要包子
[producer]正在做1个包子
[消费者A]吃了1个包子
[consumer]消费者A需要包子
[producer]正在做2个包子
[消费者A]吃了2个包子
[consumer]消费者A需要包子
2、greenlet模块实现程序间切换执行
import greenlet
def A():
print('a.....')
g2.switch() #切换至B
print('a....2')
g2.switch()
def B():
print('b.....')
g1.switch() #切换至A
print('b....2')
g1 = greenlet.greenlet(A) #启动一个线程
g2 = greenlet.greenlet(B)
g1.switch()
六、工具库文件
WebSocket
简介
从形式上看,websocket是一个应用层协议,socket是数据链路层、网络层、传输层的抽像;从应用场合上看,websocket可以使用javascript实现,而socket不能用javascript实现(真不能吗?我不太确定);从实际效果上看,和一般的socket连接用起来没什么区别。
我们知道http是短连接的,反复建立和销毁连接比较耗费资源,另外http协议经常头部内容比主体内容还长也比较浪费资源;websocket可以认为就是一个内容使用载荷固定格式的socket长连接。
websocket基本协议格式如下,更多说明见RFC 6455:
安装
pip install websockets
服务端
import asyncio
import websockets
# 检测客户端权限,用户名密码通过才能退出循环
async def check_permit(websocket):
while True:
recv_str = await websocket.recv()
cred_dict = recv_str.split(":")
if cred_dict[0] == "admin" and cred_dict[1] == "123456":
response_str = "congratulation, you have connect with server\r\nnow, you can do something else"
await websocket.send(response_str)
return True
else:
response_str = "sorry, the username or password is wrong, please submit again"
await websocket.send(response_str)
# 接收客户端消息并处理,这里只是简单把客户端发来的返回回去
async def recv_msg(websocket):
while True:
recv_text = await websocket.recv()
response_text = f"your submit context: {recv_text}"
await websocket.send(response_text)
# 服务器端主逻辑
# websocket和path是该函数被回调时自动传过来的,不需要自己传
async def main_logic(websocket, path):
await check_permit(websocket)
await recv_msg(websocket)
# 把ip换成自己本地的ip
start_server = websockets.serve(main_logic, '10.10.6.91', 5678)
# 如果要给被回调的main_logic传递自定义参数,可使用以下形式
# 一、修改回调形式
# import functools
# start_server = websockets.serve(functools.partial(main_logic, other_param="test_value"), '10.10.6.91', 5678)
# 修改被回调函数定义,增加相应参数
# async def main_logic(websocket, path, other_param)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
客服端
import asyncio
import websockets
# 向服务器端认证,用户名密码通过才能退出循环
async def auth_system(websocket):
while True:
cred_text = input("please enter your username and password: ")
await websocket.send(cred_text)
response_str = await websocket.recv()
if "congratulation" in response_str:
return True
# 向服务器端发送认证后的消息
async def send_msg(websocket):
while True:
_text = input("please enter your context: ")
if _text == "exit":
print(f'you have enter "exit", goodbye')
await websocket.close(reason="user exit")
return False
await websocket.send(_text)
recv_text = await websocket.recv()
print(f"{recv_text}")
# 客户端主逻辑
async def main_logic():
async with websockets.connect('ws://10.10.6.91:5678') as websocket:
await auth_system(websocket)
await send_msg(websocket)
asyncio.get_event_loop().run_until_complete(main_logic())
更多参考
Python3+WebSockets实现WebSocket通信 - xiondun - 博客园 (cnblogs.com)