入门基础
一:六种基本数据类型
不可变类型 | 可变类型 |
---|---|
Number(数字): | List(list) |
String(str) | Dictionary(dict) |
tuple(元组) | Set(set集合) |
1:四种数字类型:int,float, bool, complex(复数) (没有double以及Long(长整型))
判断类型的方法:
type | isinstance |
---|---|
不会认为子类是父类类型 | 认为子类是一种父类类型 |
print(type(1))
print(type(1.0))
print(type(True))
print(type(6+6j))
print(isinstance(True, bool))
print(isinstance(6+6j, bool))
>>>
<class 'int'>
<class 'float'>
<class 'bool'>
<class 'complex'>
True
False
区别
class A:
pass
class B(A):
pass
print(isinstance(A(), A))
print(isinstance(B(), A))
print(type(A())==A)
print(type(B())==A)
>>>
>True
True
True
False
截取,切片(取第一个不取最后一个)
变量(开始下标:结尾下标:符号表示查找方向,数字表示步数) |
---|
s = '12345678'
print(s[1:5]) # 取出下标1-4的
print(s[-5:-1]) # 取出下标-5:-2的
print(s[1:5:2]) # 以间隔一个数的方式取出下标1-4的
print(s[-1:5:-1]) # 反着取
print(s[2:]) # 从下标2取到结尾
>>>
>2345
4567
24
87
345678
列表相同
操作
字符串操作:
字符串格式化
牢记
len()
ord():字符 ->ASCII
cha():ASCII ->字符
str.join():拼接字符串:以str中的字符串为单位,分割括号中字符串或参数中的每个字符
print('='.join('123'))
>>>1=2=3
split():切割字符串,并保存到列表; splitlines():按行切割
print('123456'.split('4'))
>>>['123', '56']
strip():取出两侧字符(默认空白字符),可传参数去除指定字符
lstrip():只去除左边的特定字符; rstrip():只去除右边的特定字符
find():查找字符串,并返回第一次出现的下标; rfind():反向查找字符串
index():查询元素返回第一次出现的下标(若不在列表中则会报错,可以指定开始、结束范围)
replace(old, new, max):把old替换成new(新字符串),max指定最多替换次数
其他
upper():所有小写转大写; lower():所有大写转小写;
swapcase():大小写互转; capitalize():字符串首字母转大写; title():每个单词首字母大写;
isupper():判断是否为大写; islower():判断是否为小写;
isalpha():判断是否只是字母
isdigit():判断是否只是数字
isdecimal():判断是否只包含十进制字符
startswith():判断是否以特定字符开头; endswith():判断是否以特定字符结尾
isalnum():判断是否只是字母或数字
列表操作:
max(list)返回列表元素最大值
min(list)返回列表元素最小值
list(seq)将元组转换为列表
增
append(a):追加元素a
extend():将可迭代对象的元素展开追加到列表末尾
for i, v in enumerate(lt)):遍历列表以及元素下标
insert(a, b):指定a下标位置插入元素b
查
len()
index():查询元素返回第一次出现的下标(若不在列表中则会报错,可以指定开始、结束范围)
count():统计元素出现的次数
删
remove():删除指定值的元素(只删第一个)
pop():弹出指定下标的元素(默认最后一个)
clear():清空列表
其它
copy():拷贝一个列表
reverse():逆序;sort():升序排序; sort(reverse=True):降序排序; sorted():可以用于多种可迭代对象
元组操作:
len():统计长度
index():获取指定元素的下标
字典操作:
d.get():获取键值,没有返回None,可指定默认值
dict.keys():遍历字典,获取键
dict.values():遍历字典,获取值
dict.items():遍历字典,返回键值对
>>>dict_items([('a', 1), ('b', 2)])
dict.update():更新字典(存在覆盖,不存在添加)
del:删除元素; pop():删除并返回
d.clear():清空元素
集合操作:
add():添加元素
remove():删除元素(不存在会报错); discard():删除元素(不存在不会报错)
pop():随机删除并返回
clear():清空元素
s1.union(s2):求并集
s1.intersection(s2):求交集
s1.intersction_update(s2):求交集(会覆盖原来的集合)
s1.isdisjoint(s2):判断是否 没有 交集
s1.issubset(s2):判断s2是否是s1的子集
s1.issuperset(s2):判断s2是否是s1的父集(超集)
深浅复制
l1 = [1, 2, [3, 4]]
print(id(l1[0]), id(l1[2]))
l2 = l1.copy()
print('浅复制:第一层地址%d'%id(l2[0]), '内层地址%d'%id(l2[2]))
l3 = copy.deepcopy(l1)
print('深复制:第一层地址%d'%id(l3[0]), '内层地址%d'%id(l3[2]))
第一次结果:
10964896 140169666761608
浅复制:第一层地址10964896 内层地址140169666761608
深复制:第一层地址10964896 内层地址140169771593480
第二次运行结果:
10964896 140354512675592
浅复制:第一层地址10964896 内层地址140354512675592
深复制:第一层地址10964896 内层地址140354617503496
结论:浅复制列表的外层不会受到原列表的影响,但内层随着原列表的改变而改变且地址一致
深复制内外地址都不会受到原列表影响
二:函数和类
1,函数
内置对象查看:
dir(builtins)
常见函数:
len 求长度
min 求最小值
max 求最大值
sorted 排序
reversed 反向
sum 求和
进制转换函数:
bin 转换为二进制
oct 转换为八进制
hex 转换为十六进制
ord 字符转ASCII码
chr ASCII码转字符
常用高级内置函数
内置函数大全
enumerate
返回一个可以枚举的对象,代码量减少,更美观
list1 = ["1", "2", "3", "4"]
for index, item in enumerate(list1):
print index, item
>>>
0 1
1 2
2 3
3 4
eval:取出字符串中的内容,将字符串str当成有效的表达式来求指并返回计算结果
exec:执行字符串中的语句
execfile:用来执行一个文件
print(eval('1+2'))
exec("print('hello')") # 外层必须用双引号
map()
对于参数iterable中的每个元素都应用fuction函数,并将结果作为列表返回
>>> map(lambda x: x ** 2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数
[1, 4, 9, 16, 25]
filter 过滤器:filter(function, iterable)
def f(n):
return n % 2 == 1
li = filter(f, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(li)
zip 将对象逐一配对
li1 = [1, 2, 3, 4]
li2 = ['a', 'b', 'c', 'd']
print(list(zip(li1, li2)))
print(dict(zip(li1, li2)))
print(set(zip(li1, li2)))
>>>
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
{(3, 'c'), (1, 'a'), (4, 'd'), (2, 'b')}
lambda 匿名函数: lambda 参数:表达式
# 函数返回的是函数对象(地址),需要转换格式
print(list(filter(lambda x: x > 3, [1, 2, 3, 4, 5])))
print(list(map(lambda x: x+1, [1, 2, 3, 4, 5])))
函数作用域
global(全局变量) 用在第一层函数,用于修改函数外部变量
nonlocal(局部变量) 用在内层函数,用于修改外层函数变量
闭包和回调函数
嵌套函数:
def fun1():
print('fun1()在被调用')
def fun2():
print('fun2()在被调用')
fun2()
fun1()
>>>
fun1()在被调用
fun2()在被调用
闭包
f1(2)() 也可以调用内层函数
def f1(a):
b = 10
print('这是外层函数')
def f2():
print('这是内层函数')
print(a+b)
return f2
f1(2) # # 函数名加括号才能调用,返回f2不能调用,需要加括号
>>>
这是外层函数
f =f1(2)
f()
>>>
这是外层函数
这是内层函数
12
递归 :虽然代码简洁,但是占用内存高
def f1(i):
if i == 1:
return 1
return f1(i-1)*i
print(f1(5))
回调:根据参数,是否在一个函数中调用另一个函数
def choice(callback, b):
if b:
callback()
else:
print('未回调')
def play():
print('回调')
choice(play,0)
形参和实参
def foo(x, y, z):
print("x=", x)
print("y=", y)
print("z=", z)
#调用函数
foo(1,3,5) #此处的1,3,5是实参
2,类定义,属性,初始化和析构
class A:
var = '类属性'
# 二个下划线(私有属性)外部不可以直接访问,但是私有属性可被其子类继 _a = 1
__b = 2
def f(self): # 通常,将默认会传入的那个参数命名为self,用来表示调用这个方法的实例对象本身。
print('类方法')
a = A() # 类的实例化 a就是A的实例
print(a.var) # 调用类的属性
a.f()
析构函数:
class B:
def __init__(self, self.name):
self.name = name
b = class('无名') # 实例化类的时候自动调用析构函数
销毁机制 (析构函数)
class A:
def __init__(self, name):
self.name = name
print(self.name)
def __del__(self):
print(self.name,'实例被销毁了,之后无法再使用')
a = A('lc')
del a
方法的重写:
class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
# 有两种方法:用子类对象调用父类已被覆盖的方法
Parent.myMethod(self) # 1
super(Child,c).myMethod() # 2
# super() 函数是用于调用父类(超类)的一个方法。
>>>
调用子类方法
调用父类方法
类在生成时会自动生成方法解析顺序,可以通过 类名.mro()来查看
魔术方法
__call__方法:调用类的实例
__new__方法:
1、__new__方法是在类创建实例的时候自动调用的。
2 先调用__new__方法创建实例,再调用 __init__方法初始化实例。
3 __new__方法,后面括号里的cls代表的是类本身
class A:
def __init__(self):
print('析构方法')
def __new__(cls, *args, **kwargs):
print(cls)
return cls
a = A()
b = A()
print(id(a))
print(id(b))
>>>
<class '__main__.A'>
<class '__main__.A'>
2214118711752
2214118711752
class A:
def __init__(self):
print('析构方法')
def __new__(cls, *args, **kwargs):
return super().__new__(cls)
a = A()
b = A()
print(id(a))
print(id(b))
>>>
析构方法
析构方法
1873618655384
1873618702520
class A:
def __init__(self, name):
self.name = name
# print('123')
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'instance'): # hasattr:判断类cls中是否存在类属性instance
# not 0 返回 1
cls.instance = super().__new__(cls) # 调用父级创建实例(开辟地址)
return cls.instance # 若存在此属性,则直接返回上一次所创建的内存地址
a = A("LC")
b = A("NAME")
a.age = 18 #
print(id(a))
print(id(b))
print(a.age)
print(a.name)
print(b.name) # 地址相同,互相影响,前一次创建的实例属性会被覆盖
>>>
1706951990128
1706951990128
18
NAME
NAME
__str __方法
当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
class Person:
def __init__(self, new_name, new_age):
self.name = new_name
self.age = new_age
def __str__(self):
return "%s的年龄是:%d"%(self.name, self.age) # print(实例名)
def play(self):
print("game")
def study(self):
print("java")
a = Person("LC", 20)
b = Person("CL", 18)
print(a)
print(b)
>>>
LC的年龄是:20
CL的年龄是:18
__repr __方法:
打印出实例所引用的对象
class A:
def __init__ (self, name, price):
self.name = name
self.price = price
# 创建一个Item对象,将之赋给im变量
a = A('name', LC)
# 打印im所引用的Item对象
print(im)
>>>
<__main__.Item object at 0x000001B34B769278>
__call __方法:(实例名+括号将会触发此方法)
了解魔术方法:
1、__class__ 查看类名
格式: 实例.__class__
2、__dict__ 查看全部属性,返回属性和属性值键值对形式
格式:实例.__dict__
3、__doc__ 查看对象文档,即类中(用三个引号引起来的部分)
格式:类名.__dict__
4、__bases__ 查看父类
格式:类名.__base__
5.__mro__ 查看多继承的情况下,子类调用父类方法时,搜索顺
格式:子类名.__mro__
实例.__class__.__mro__
装饰器
闭包+回调
def outer(f1):
print('这是外层函数')
def inner():
print('这是内层函数')
f1()
return inner
def func():
print('这是func')
f = outer(func)
f()
>>>
这是外层函数
这是内层函数
这是func
装饰器:
def outer(f1):
print('这是外层函数')
def inner():
print('这是内层函数')
f1()
return inner
# @outer 相当于 outer(func)
@outer
def func():
print('这是func')
func()
自带装饰器:
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
areas = self.length * self.width
return areas
@property # 就像访问属性一样
def area(self):
return self.width * self.length
@staticmethod # 静态方法 和class类断开联系
def func(): # self 在调用的时候会报错
print(‘staticmethod func’)
@classmethod # 类方法
def show(cls): # cls 代表类本身
print(cls)
print('show fun')
class A:
name = 'LC'
@property # @property:像访问类属性的方式来访问方法(不需要加括号)
def area(self):
print('这个是area')
@staticmethod # 不会自动传类的实例(不用传参)
def func():
print('这个是func')
@classmethod # @classmethod:使cls=A,直接打印出类本身而不是类的实例
def show(cls):
print(cls)
print(A)
print('这个是show')
a = A()
print(a.name)
# a.area()
a.area
a.func()
a.show()
>>>
LC
这个是area
这个是func
<class '__main__.A'>
<class '__main__.A'>
这个是show
类的装饰器:
class TestClass:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('类')
return self.func
@TestClass
def fun_test():
print('这个是函数')
f = fun_test()
f()
三:应用基础
文件编程
file.flush()
刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。
file.seek(offset, whence)
offset -- 开始的偏移量,也就是代表需要移动偏移的字节数,如果是负数表示从倒数第几位开始。
whence:可选,默认值为 0。给 offset 定义一个参数,表示要从哪个位置开始偏移;
0 代表从文件开头开始算起,1 代表从当前位置开始算起,2 代表从文件末尾算起。
文件的复制
with open('test.txt', 'r') as f1,\
open('test_copy.txt', 'w') as f2:
content = f1.read()
f2.write(content)
OS编程
错误和异常
raise用于抛出异常,指定异常位置(报错)
断言
断言语句是将调试断言插入程序的一种便捷方式
assert 的语法规则是:
表达式返回 True 不报错
表达式返回 False 报错 报 AssertionError
assert 1 == 1
assert 1 == 2 报错
>>>
assert 1 == 2
AssertionError
迭代器和生成器
迭代:每一次循环都会自动让“迭代变量”指向“下一个元素
创建一个迭代器:
__iter__() 方法返回一个特殊的迭代器对象,
这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
__next__() 方法会返回下一个迭代器对象。
li = [1,2,3,4,5,6]
myiter = iter(li)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
>>>
1
2
3
4
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
>>>
1
2
3
生成器(yield与迭代)
return 返回后就结束
yield 返回后暂停,直到下一次触发生成器
斐波那契数列:第三个数字始终为前两个数字之和
def fi(max):
a, b, count = 0, 1, 0
while count < max:
yield b
a, b = b, a+b
count += 1
max = 6
n = fi(max)
try:
for i in range(max):
print(next(n), end=' ')
except EnvironmentError as e:
raise e
>>>
1 1 2 3 5 8
模块
import … as …
导入以后,重新命名
sys.path
用于存放导入路径的列表
类似于环境变量中的 PATH
添加路径用sys.path.append(‘所创模块路径’)
__ init__.py:
在包管理中,加入此模块,则包名可以直接通过属性访问的方式,访问此模块内的对象,
此模块不加上可能不会报错,但是规范是要加上,文件内容可以为空
print(sys.argv)
获取当前绝对路径
python进阶基础
1:正则表达式
re.match函数
re.match 尝试从字符串的起始位置匹配一个模式,
如果不是起始位置匹配成功的话,match()就返回none。
re.match(pattern, string, flags=0)
re.search方法
re.search 扫描整个字符串并返回第一个成功的匹配。
re.search(pattern, string, flags=0)
findall
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 ,findall 匹配所有。
语法格式为:
findall(string[, pos[, endpos]])
参数:
string 待匹配的字符串。
pos 可选参数,指定字符串的起始位置,默认为 0。
endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
正则表达式修饰符
修饰符 | 作用 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
正则表达式元字符:
单字符匹配:
多字符匹配:
边界匹配
分组匹配:
贪婪和非贪婪匹配:
import re
content = '<html>123</html>彩虹六号<td>789</td>'
print(re.findall(r'<.*>',content)) # 贪婪匹配全部,尽可能多的匹配符合要求的数据
print(re.findall(r'<.*?>',content)) # 非贪婪匹配最短
print(re.findall(r'>.*?<',content)) # 非贪婪按最短匹配
>>>
['<html>123</html>彩虹六号<td>789</td>']
['<html>', '</html>', '<td>', '</td>']
['>123<', '>彩虹六号<', '>789<']
2:Json, hashlib以及base64模块
json
重要区别: 字符串必须用双引号(即:””)来包括
Python 编码为 JSON 类型转换对应表:
json只有数组格式,转python格式时不能转为元组
import json
data = (
1,2,3,4,5
)
json_str = json.dumps(data) # python转json
print(json_str)
print(data)
print(json.loads(json_str)) # json转python
>>>
[1, 2, 3, 4, 5]
(1, 2, 3, 4, 5)
[1, 2, 3, 4, 5]
json.dump(obj, fp)转换为json并保存到文件中
json.load(fp)从文件中读取json,并转化为python数据
hashlib
主要算法:
1.md5
2.SHA系列:sha1, sha224, sha256, sha384, sha512
hashlib模块API
base64(url编码)
base64模块API
对字符串编码解码:
import base64
data = 'python'.encode()
# 编码
data_encode = base64.b64encode(data)
print(data_encode)
# 解码
data_decode = base64.b64decode(data_encode)
print(data_decode)
对url编码解码:
url_encode = base64.b64encode(url.encode()) # 编码类型必须是bytes类型
3:datetime与logging模块
datetime模块:
常用格式
import datetime
print(datetime.datetime.now()) # 获取当前时间
print(datetime.datetime.now().timestamp()) # 将时间日期转化为时间戳
print(datetime.datetime.fromtimestamp(1563350340.731763)) # 将时间日期转化为时间戳
print(datetime.datetime.now().strftime('%Y-%m-%d-%H(%I)-%M-%S'))
>>>
2019-07-17 16:02:50.033486
1563350570.033486
2019-07-17 15:59:00.731763
2019-07-17-16(04)-02-50
时间计算datetime.timedelta()
datetime.timedelta( days=0,
seconds=0, microseconds=0 milliseconds=0,
minutes=0, hours=0, weeks=0 )
now_time = datetime.datetime.now()
print(now_time)
print(now_time.strftime('%d'))
print(now_time + datetime.timedelta(days=1))
print(now_time + datetime.timedelta(weeks=1))
print(now_time + datetime.timedelta(weeks=1))
>>>
2019-07-17 17:01:29.215863
17
2019-07-18 17:01:29.215863
2019-07-24 17:01:29.215863
2019-07-24 17:01:29.215863
logging模块
日志等级:
Formatter格式
模块组件化
代码流程:
import logging
# 第一步:创建一个logger(实例化对象)
logger = logging.getLogger('logging') # 检测的文档文件名
logger.setLevel(logging.DEBUG) # 设置级别
# 第二步:负责发送信息到目的地,方向有文件,或控制台
sh = logging.StreamHandler() # 输出到控制台
sh.setLevel(logging.DEBUG) # 设置级别,高于此级别的会被输出
fh = logging.FileHandler('logger.txt','w+') # 输出到文件
fh.setLevel(logging.DEBUG) # 设置级别,高于此级别的会被输出
# 第三步:定义日志格式,输出日志格式
formatter = logging.Formatter('时间:%(asctime)s, 日志信息:%(message)s') # 参照格式表
# 把定义的格式导入到控制台或文件中
sh.setFormatter(formatter)
fh.setFormatter(formatter)
# 添加
logger.addHandler(sh)
logger.addHandler(fh)
# 获取级别
if __name__ == '__main__':
logger.debug('debug')
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
线程
进程和线程的区别
进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;或者更专业化来说:进程是指程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。
线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。进程——资源分配的最小单位,线程——程序执行的最小单位。
关系
1、一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。
2、资源分配给进程,同一进程的所有线程共享该进程的所有资源。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
3、处理机分给线程,即真正在处理机上运行的是线程。
4、线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
重写继承的Thread类:
class MyThread(Thread):
def __init__(self, name, *args, **kwargs):
super().__init__(*args, **kwargs) # 重写继承的Thread类
self.name = name
def run(self): # 线程启动的时候调用
print('hello{}'.format(self.name))
time.sleep(3)
print('bye')
my_Thread = MyThread('LC')
my_Thread.start()
>>>
helloLC
bye
进程详解:
from threading import Thread
import time
def f1():
print('函数1')
time.sleep(3)
print('函数1over')
def f2():
print('函数2')
time.sleep(2)
print('函数2over')
if __name__ == '__main__':
print('主线程执行中')
f1_thread = Thread(target=f1)
f2_thread = Thread(target=f2)
f1_thread.start()
f2_thread.start()
print('主线程执行完毕')
>>>
主线程执行中
函数1
函数2
主线程执行完毕
函数2over
函数1over
join : 阻塞调用程序 , 直到调用join () 方法的线程执行结束, 才会继续往下执行
if __name__ == '__main__':
print('主线程执行中')
f1_thread = Thread(target=f1)
f2_thread = Thread(target=f2)
f1_thread.start()
f2_thread.start()
f1_thread.join()
f2_thread.join()
print('主线程执行完毕')
>>>
主线程执行中
函数1
函数2
函数2over
函数1over
主线程执行完毕
setDaemon() 与 join() 基本上是相对的 , setDaemon不会等待其他线程
if __name__ == '__main__':
print('主线程执行中')
f1_thread = Thread(target=f1)
f2_thread = Thread(target=f2)
f1_thread.setDaemon(True)
# f2_thread.setDaemon(True)
f1_thread.start()
f2_thread.start()
# f1_thread.join()
# f2_thread.join()
print('主线程执行完毕')
>>>
主线程执行中
函数1
函数2
主线程执行完毕
函数2over # 因为 函数1执行时间为3s,2s的函数2执行完之后不会等待
互斥锁(控制共享资源的访问)
线程的加锁解锁
from threading import Thread, Lock
data = 0
def add_1():
global data
lock.acquire()
for i in range(1000000):
data += 1
lock.release() # 解锁
def rea_1():
global data
lock.acquire()
for i in range(1000000):
data -= 1
lock.release()
if __name__ == '__main__':
lock = Lock()
t1 = Thread(target=add_1)
t2 = Thread(target=rea_1)
t1.start()
t2.start()
t1.join() # 线程之间抢资源
t2.join()
print(data)
>>>
0
队列
入队: put(item)
出队: get()
测试空: empty()
测试满: full()
队列长度: qsize()
任务结束: task_done()
等待完成: join()
线程池
from threading import Thread
from queue import Queue
import time
class ThreadPool:
def __init__(self, n): # n为池内线程数
self.q = Queue() # 实例化队列
for i in range(n):
Thread(target=self.worker, daemon=True).start() # daemon守护线程
def worker(self): # 取出线程并实现
while True:
func, args, kwargs = self.q.get() # 取出数据
func(*args, **kwargs) # 运行任务
self.q.task_done() # 结束线程
def put_q(self, func, *args, **kwargs): # 将线程放入队列
self.q.put((func, args, kwargs))
def join_q(self): # 阻塞等待线程
self.q.join()
def f1(*args, **kwargs):
print('这是任务一{}'.format(args))
time.sleep(3)
print('任务一结束{}'.format(kwargs))
def f2():
print('这是任务二{}')
time.sleep(4)
print('任务二结束{}')
if __name__ == '__main__':
pool = ThreadPool(1)
pool.put_q(f1, *(1,2,3), **{'a':1,'b':2,'c':3})
pool.put_q(f2)
print('提交任务')
pool.join_q() # 等待所有任务执行完成
print('所有任务执行完毕')
>>>
提交任务
这是任务一(1, 2, 3)
任务一结束{'a': 1, 'b': 2, 'c': 3}
这是任务二{}
任务二结束{}
所有任务执行完毕
操作一: close - 关闭提交通道,不允许再提交任务
操作二: terminate - 中止进程池,中止所有任务
内置池
from multiprocessing.pool import ThreadPool
import time
def f1(*args, **kwargs):
print('lc1 love {}'.format(args))
time.sleep(2)
print('lc1,over {}'.format(kwargs))
def f2():
print('LC2')
time.sleep(2)
print('LC2,over')
if __name__ == '__main__':
pool = ThreadPool(2)
pool.apply_async(f1, args=(6,6),kwds={'a':3,'b':4})
pool.apply_async(f2)
print('任务提交完成')
# pool.terminate() # 终止所有线程
pool.close() # 不能再提任务了,必须在join之前
pool.join()
print('所有任务都完成')