python 学习笔记

python学习笔记  留作记录

Python 笔记
操作命令符:
cd 打开指定路径

2.dir 浏览目录
3.mkdir 创建新目录
4.rmdir 删除目录
5.Ipconfi 查看 ip
6.Ping 测试网络连接

> python
> 计入 python 环境 写 python 程序
>
> > exit() 退出环境

> pip list 列出匹配管理包列表
> pip install <name> 安装包
> pip uninstall <name> 卸载包
> pip -V 查看版本
> pip freeze > requirements.txt 将项目依赖的包输出到指定的 requirements.txt
> pip install -r requirements.txt   使用 Pip 安装 requirements.txt 中所包含的依赖包

1.Runtime error 缺失程序 python windows 少了补丁
2.Python 环境变量 3.升级 pip python -m pip install --upgrade pip

进入环境:
终端输入:
Python:写 python 代码
python 源文件:xxx.py 拓展名是 py

交互式 和 源文件

单词:
Print()打印
Define(define)定义
syntaxError 语法错误
nameError 名字错误
Invaild 无效的
Character 字符
file 文件
Directory 文件夹

变量替换字符串实例方法:

print(value...,sep='',end='\n'):输出
sep= 默认间隔字符' '
end= 末尾默认字符'/n'

'''
%d 等等等
%s 等等等
%f 等等等
''' %(arg1,arg2,arg3)

'{}等等等等等等{}等等等'.format(arg1,arg2)

类型转换:
int——str
Str——int

imput() 输入:阻塞式
Name = input('提示语')
str in str 字符串是否在另一个字符串里面
str not in str 字符串是否不在另一个字符串里面
id()返回传入参数的内存地址编码
is()对比两个对象的是否完全相同

运算符种类:
赋值运算符 =
算数运算符 + - \* /
关系运算符 < > <= >= == !=
逻辑运算符 and or not
位运算符

python 对小整数的定义是[-5,256](包括基本字母字符)对这些整数对象是提前建立好相应的内存编码,当内容数值是相同的时,都是使用的同一个内存地址,以避免频繁注册及销毁;
在源文件中 内容相同的数据是直接使用同一个内存地址(不论大小)
在 python 解释器中超出指定范围的数字及字符则会重新注册创建

bin(num) 将十进制转换为 2 进制

三目运算符
(当结果为 true 时) if(a>b) else (当结果为 false 时)

逻辑判断:
if():
xxx
elif():
xxx
else:
xxx

random 随机数:
import random
random.randint(start,end)

单词:
help 帮助
function 函数
built-in(builtins)内置
Module 模块
Value 值
Stream 流
Default 默认的
Format 格式化
digit 数字 %d
Required 必须 需要
Raise 抛出 扔出
Operator 运算符
identity 特征 身份

循环语法:
for 变量名 in 集合:
语句

range(start,end,num) 获取指定范围内的数值,第三个参数为间隔范围,默认为 0 开始,含头不含末尾的值

pass 补全语句的占位符,防止逻辑结构不全报错

break 终止循环语句

单词:
Convert 转换 转变
During 在...期间(之间)
Range 范围
integer 整型
Sequence 序列 队列
include 包含
Exclude 不包含

字符串内置方法
len(str) 返回 str 的字符串长度 length
str.upper() 字符串大写
str.lower() 字符串小写
str.find('str',start ,end) 字符串查找方法 当找到时返回字符串 index 没找到返回-1
str.rfind()
str.lfind()
str.index()
str.rindex()
str.lindex()
str.replace('old','new',num) 字符串替换方法 查找并替换字符串中的内容,num 为替换的次数

编码 解码
str.encode('utf-8') 将内容编码
code.decode('utf-8') 将内容解码
返回值都是布尔类型 True Flase
str.startswith() 判断 str 是否以 xxx 开头
str.endswith() 判断 str 是否以 xxx 结尾

str.isalpha() 判断是否是字母
str.isdigit() 判断是否是数字

''.join(ArrList) 将符号插入队列中,主要功能将数组转换为字符串

str.strip() 去除前后指定字符串
str.lstrip() 去除字符串左侧指定字符
str.rstrip() 去除字符串右侧指定字符

str.split('') 将字符串切割指定字符,并返回新数组
str.count('') 求字符串中指定的 args 的个数

str in strAll 判断一个字符串里是否包含另一个字符串

del arr[i] 删除数组中的某一项

json.dumps() 将数据转换为 json 字符串
json.loads() 将 json 字符串还原

max([arr]) 最大值
min([arr]) 最小值

sorted(list,reverse = True) 排序
list(string) 将字符串转换为列表

列表添加:
[].append() 末尾追加
[].insert() 指定位置插入
[].extend() 一次添加多个元素
列表删除:
del list[i]
remove()
pop()
clear()
列表排序:
list.sort() sorted(list) 升序排序
list.reverse() 降序排序
list[::-1] 列表取反

enumerate():函数用于将一个可遍历数据对象(如列表、元组、字符串)组合为一个索引序列
for index,value in list:
print(index,value)

列表总结:
list:

- 合并 []+[]

* []\*n

in 数据 a 是否在列表 b 中
not in
is 内存地址是否相同
not is

max()
min()

enumerate 枚举 index value in enumerate(list):

元组
()不可修改
tuple()将元素转换为元组类型 +
*
is not
in not in
max()
min()
sum()
len()
sorted()
a,*b,c=[arr,2,3,3,4,4] \*表示未知个数的元素 在解构赋值中获取多余的元素

字典:dictionary
dict = {} 与对象使用方法差不多,其 key 值用引号括起
obj = {
'name':'heihe',
'age':22
}
添加元素(key:value):
dict[key] = value --->{key:value}
特点:key 在字典中是唯一的

字典里的函数:items() values() keys()

# for key, value in dist.items():

# if value >= 80:

# print(key)

items 方法调用时可以加入 key,value 将键值对遍历出来,如果只有一个参数那么就会将字典的键值对转成列表保存的形式[(key,value),(key,value)]

dict.get('value',default) 用 get 获取字典中的 value 值 如果不存在则默认返回 None 默认值可修改

删除
del dict['key']
dict.pop('key',default) 用 pop 删除指定的键值对 如果不存在则返回默认值
dict.popitem() 从末尾删除键值对
dict.clear 清空字典所有内容
dict.update() 将多个字典合并 //Objcet.assign
dict.fromkeys(Array, default) 将列表转换为字典,第二个参数 Value 的默认值

集合---无序不重复的序列
声明集合:set

setlist.add(any) 给集合无序添加元素 将添加的元素以一个整体加入集合中
setlist.update() 将添加的元素 结构为零散元素添加入集合中
setlist.remove('key') 删除指定元素
setlist.pop() 在集合中 pop 删除第一个元素
setlist.clear() 清空

setlist.discard(num) 删除指定元素,当元素不存在是不会报错
== 判断两个集合是否相等 判断的是集合中的 value

- 或者 difference() 集合可以用减号求取差集
  & 或者 intersction() 求取集合的交集
  | 或者 union() 求取集合的并集
  ^ 或者 symmetric_difference() 求取集合的不同元素

可变和不可变的
不可变类型: int str float 元组 tuple
可变类型:list 列表 set 集合 dict 字典

isinstance(obj,type) 判断传入的 obj 类型是否是 type

可变和不可变:
list set dict 三个为可变(内容可变,其内存地址不变)
str int float tuple frozenset 为不可变(内容不可变,其内存地址会变化)

类型转换:
str-->list set ...相互转换
list --> set tuple dict 相互转换

函数:
增加代码复用性,减少代码的冗余

def FunctionName(argumens):
FunctionBody

argumens 形参列表
可谓*arg:为传入参数数目不可定;
(arg1,*arg):arg1 为参数 1,其后身下的参数为\*arg (注意,可变参数必须放在固定参数的后边) **传入为元组**
(arg1,arg2,arg3) 如果要忽略参数 arg2,直接给 arg3 赋值,需要是用关键字进行赋值(1,arg3=10)
(**args) **两颗星+argumentsName 关键字赋值参数,可以传入随意个数的参数,在调用时需要使用键值对,在函数内部接受结果为字典类型
FunctionName(**dict) 在调用函数时 使用**双信号字典时,系统会自动将传入参数解构至单元键值对自动传入对应函数中**传入为字典**
def getMessage(**args):
print(args)
dict1 = {'name':'卧槽','age':888,'hoppy':'smoke'}
getMessage(**dict1)

当传入实参*list[] 列表前加*号时,将列表拆成单个参数传入函数中

函数内部修改全局参数时 全局参数为可变参数时(list、set、dict)直接调用参数(str、int、float、tuple)时需要在名前加上描述:global 之后才可进行全局修改

内部函数调用修改外层函数的变量时 需要与内部函数区分 加上描述:nonlocal 之后才能修改

a= 100
def func():
b = 200
def inner_func():
nonlocal b
global a
c= 300
b+=1
a+=2
print(a,b,c)
inner_func()
func()
//102 201 300

locals()查看本地变量有哪些,以字典形式输出
golbals() 查看全局变量有哪些,以字典形式输出(包含系统自带键值对)

闭包:
外层函数返回内层函数(内层函数不调用),内存函数返回被保护的变量
在全局调用外层函数

def func():
a = 0
def inner_func():
nonlocal a
a+=1
return a
return inner_func

x = func()
print(x())
print(x())

装饰器:
@decorate
def house():
pass

1.house 被装饰函数 2.被装饰函数作为参数传入装饰器 decorate 3.执行 decorate 函数 4.将返回值赋值给 house

双层装饰器:
@deracotor2
@deracotor1
def house(\*arg,\*\*kwargs):
print('这是一个 base house')

    双层装饰器调用时,谁离装饰函数越近就越先被调用

装饰器带参数
带参数的装饰器是三层的
最外层的函数负责接收装饰器参数
里面的内 ring 还是原装装饰器的内容\

函数作用域:
LEGB
L:local 本地
E:encloseing 嵌套
G:global 全局
B:built-in 内置的

匿名函数: lambda

内置函数: 在大多数情况下 结合 lambda 使用内置函数 效果最佳
max list(max(list1,lambda key=x:x['a']))
map list(map(lambda x:x+1,list1))
reduce list(reduce(lambda x,y:x+y,list1)) from functools import reduce 该函数需要单独引用
filter list(filter(lambda x: x>3,list2))
sorted list(sorted(list1,key=lambda x: x['b']))

    文件操作:
    file=>文件路径
    mode=>r(rt读入文本),w(wt写入文本),rb(读入二进制),wb(写入二进制),a(append 写入内容为追加,不会重置写入内容)
    buffer=>所占内存
    open(file,mode,buffer)
        读取:
        stream = open('test.txt',encoding='utf-8')
        stream.read() 从流中将文件内容读取出,该目录下其他操作符无效
        stream.readline()  读取一行 每打印一次行数+1
        stream.readlines() 读取全部内容
        stream.readable() 查看文件是否可读取
        mode ='rb' 读取内容格式为2进制 (当文件类型不是默认文本类型时,修改参数mode为'rb')

        写入:
        stream = open('test.txt',mode='w',encoding='utf-8')
        stream.writable()是否可写入
        stream.write() 写入相应的内容(每次进行写入操作时都会先将内容清空)
        stream.writelines('[]') 写入一行的内容(写入的内容以列表形式写入)

        追加:
        mode = 'a'
        写入的内容不会被重置

OS 模块 (operating system)

os.path.dirname(**file**) 查询当前页面所在文件夹

os.path.join(path,'filename' ) 根据参数中的路径 拼接文件名

path = os.path.abspath('test.txt') 查询指定文件的绝对路径
path = os.path.abspath(**file**) 查询当前文件所在绝对路径

os.path.isfile('name') 判断是否是文件
os.path.isdir('name') 判断是否是文件夹

os.path.split(path) 切割路径 获得文件名
os.path.splitext(path) 切割路径 获得拓展名(可用来判断文件类型)

os.path.size(name) 返回文件的大小

os.getcwd() 获取当前目录
os.listdir('hehe') 浏览文件夹
os.mkdir('name') 新建文件夹
os.removedirs('name') 删除文件夹
os.remove('name')删除文件
os.chdir('name') 切换文件路径

异常处理:
try: 可能出现错误的代码
except Exception as e: 如果有异常执行的代码
finally: 无论是否存在异常都要执行的代码

列表推导式:
[i for i in list] or [i for i in list if i 条件]

定义生成器方法 generator: 1.通过列表推到方式
g = (x\*3 for x in range(10))
调用 g.**next**() 时,将自动生成下一个对应的数值,从而减少内存的使用 2.函数+yield
步骤: 1.定义一个函数,函数中使用 yield 关键字 2.调用函数,接受调用的结果 3.得到的结果就是生成器 4.借助 next() **next**() 得到元素

def func():
n = 0
while True:
n += 1
yield n
g = func()
print(next(g))
print(g.**next**())

**next**():获取下一个元素
next(generator):每次调用都会产生一个新的元素,如果元素产生完毕,再次调用会抛出错误
sent(value):向每次生成器调用中传值 注意:第一次调用 send(None)

# 斐波拉契数列 生成器方法

def fib(num):
a, b = 0, 1
n = 0
while n < num:
g = yield b
if g:
print(str(g)+'..wocao')
a, b = b, a+b
n += 1
return 'none'

g = fib(10)
for i in g:
if(i % 2 == 0):
g.send(i)

迭代是访问集合元素的一种方式,迭代器是一个可以记住遍历的位置的对象,迭代器对象从集合的第一个冤死开始访问,直到所有的元素被访问完结束,迭代器只能往前不会后退。
可以被 next()函数调用并不断返回下一个值的对象称为迭代器:Iterator.(生成器是可迭代的,也是迭代器,list 是可迭代的,但不是迭代器)

iter(iterator) 将可迭代变为迭代器

类方法:
特点: 1.定义需要依赖装饰器@classmethod 2.类方法中的参数不是一个对象,而是类本身 3.类方法中只可以使用类属性 4.类方法中不可使用普通方法 5.类方法中可同步调用类方法 6.类方法是不依赖对象的,类方法是在普通方法前初始化 7.普通方法可以用类名.方法名全局调用类方法
类方法的作用:
因为类方法只能访问类属性和类方法,所以可以在对象创建之前需要完成一些动作(功能)

class 类的使用
\_\_name 加下划线的属性为私有属性,只可在内部调用

静态方法:很类似类方法 1.需要装饰器 staticmethod 2.静态方法无需传递参数<cls,self> 3.也只能访问类的属性和方法,对象的是无法访问的 4.加载时机同类方法
总结:
类方法 静态方法
不同: 1.装饰器不同 2.类方法是有参数的,静态方法没有参数
相同: 1.只能访问类的属性和方法,对象的是无法访问的 2.都可以通过类名进行调用访问 3.都可以在创建对象之前使用,因为是不依赖于对象、

普通方法 与两者的区别:
不同: 1.没有装饰器的 2.普通方法依赖对象,因为每一个普通方法都有一个 self 3.只有创建了对象才可以调用普通方法,否则是无法调用的。

#魔术方法
**init**:初始化魔术方法
触发时机:初始化对象时触发(不是实例化触发,但是和实例化在一个操作中)

    __new__:实例化的魔术方法
    触发时机:在实例化时触发
    作用:开辟内存空间

    __call__:对象调用方法
    触发时机:将对象当成函数使用的时候 会默认调用此函数中的内容

    __del__:析构魔法方法
    触发时机:当对象没有用(没有任何变量引用)的时候触发
    def obj  删除obj地址的引用
             当一个空间没有了任何的引用时,将会默认执行__del__
             ref失灵 是因为该目标没有任何引用
    __str__:打印对象名 自动触发去调用__str__里的内容  注意:需要return 返回
    单词打印对象是返回的是一个内存地址,对于开发者来说作用不大,如果想打印对象名的时候能够给开发者更多一些信息量使用__str__。

sys.getrefcount() 查询调用目标内存被引用的个数(本次查询也被记录在结果中)

魔术方法重点:**init** (构造方法,创建空间后的第一个调用 ) **str**
了解:**new** 自定义开辟空间时的设置(80%不需要重写) **del** 没有引用时会自动调用重写(99%不需要重写) **call** 想不想将对象当函数调用

大总结:
普通方法
def 方法名(self,[参数]):
pass
对象.方法()

类方法 @classmethod
def 方法名(cls,[参数]):
pass
类名.方法()
对象.方法()
静态方法 @staticmethod
def 方法名([参数]):
pass
类名.方法()
对象.方法()
魔术方法

私有化:(demo0313.py)
封装:1.私有化属性 2.定义共有 set 和 get 方法
\_\_属性:就是讲属性私有话
好处:1.隐藏的私有化属性不被外界随意修改 2.也可以修改,通过函数
def setXXX(self,xxx): 3.筛选赋值的内容
if xxx 就否符合相应的条件
赋值
else:
不赋值 3.如果想获取具体的某个属性 使用 get 函数
def getXXX(self,xxx):
reutnr xxx

通过 dir(Person) 可查看文件所有的属性,其中包括私有属性内容,其实他是的私有属性通过系统进行自动改名

@property 私有属性装饰器
def xxx(self):
pass
用@property 装饰器修饰私有变量 xxx

@xxx.setter
def xxx(self,new):
self.xxx=new

用属性 xxx.setter 作为装饰器 修饰私有变量的修改方法

知识点:
1.has a 一个类中 使用了另外一种自定义类型
student 使用了 computer book
2.is a
类型:
系统类型:
str int float list dict tuple set
自定义类型:
class 算是自定义的类 都可以将其当成一种类型
s = Student() s 是 Student 类型的对象

继承:(demo0313.py)
Doctor,Worker,Police 都属于人类 Person
相同的代码 代码冗余,可读性不高

将相同代码提取->Person
Doctor,Worker,Police ->都继承 Person

super()表示父类对象
特点:(demo0314.py) 1.如果类中不定义**init**,调用父类 super class 的**init**(params) 2.如果类继承父类也需要定义自己的**init**,就需要在当前类型的**init**调用一下父类的**init** 3.如何调用父类的**init**:
super().**init**(参数)
super(type,对象).**init**(参数) 4.如果父类有 eat(),子类也定义一个 eat 方法,默认搜索的原则:先找到当前类,再去找父类
s.eat()
override:重写(覆盖)
父类提供的方法不能满足子类的需要,就需要定义一个同名的方法,这个行为就称为:重写 5.子类的方法也可以调用父类方法:
super().方法名(参数)

import inspect
inspect.getmro(Class) 或者 Class.**mro** 查询类属性的调用层级关系

python 允许多继承,调用原则为广度优先
def 子类(父类 1,父类 2):
pass

总结:

私有化:封装 将属性私有化,定义公有化 set 和 get 方法
def setAge(self,age):
判断
def getAge(self):
return self.\_\_self

s.setAge(20)
s.getAge()

class Student:
def **init**(self,age):
self.**age = age
@property
def age(self):
return **age

@age.setter
def age(self,new)
self.\_\_age = new

s = Student(20)
s.age(30) 设置私有属性 AGE
s.age() 获取私有属性 AGE

继承:
has a 包含继承
class Student:
def **init**(self,name,book): //name book 都为实例化类  
 pass
is a 继承
正常类的继承方法

python 的多态是类似于多态的方式,用 isinstance 进行判断
isinstance(obj,类) 判断 obj 是不是这个类 或者是这个类的子类

多态:简单来说就是允许子类类型的指针赋值给父类类型的指针

单例:
自定义控制内存空间的创建,从而减少内存的使用
class Person:
\_\_that = None

    def __new__(cls):
        if cls.__that == None:
            cls.__that = object.__new__(cls)
            return cls.__that
        else:
            return cls.__that
    p = Person()
    p1 = Person()

1.自定义模块 2.使用系统一些模块

导入模块:
1.import 模块名
模块名.变量 模块名.函数 模块名.类
2.from 模块名 Import 变量|函数|类
3 from 模块 import \*  
 引入该模块中所有的内容,但是如果想限制获取的内容**all**=['允许被导出的模块'] 4.无论是 import 还是 from 的形式,都会讲模块内容进行加载,如果不希望其进行调用,就会用**name**
在自己的模块里面**name**叫:**main**
如果在其他模块中通过导入的方式调用的话:**name**:模块名(在其他模块引入原模块时,**name**值为原模块名字,在原模块中调用时
**name**值为'**main**')

文件 包 (demo0318.py)
非 py 文件 包:py 文件
一个包中可以存放多个模块
项目>包>模块>类 函数 变量

from 包 import 模块
from 包.模块 import 类|函数|变量
from 包.模块 import \* (**all** = [])

**init**.py 文件
当导入包的时候,默认调用**init**.py 文件
作用: 1.当导入包的时候,把一些初始化的函数,变量,类定义在**init**.py 文件中 2.此文件中函数,变量等的访问,只需要通过包名,函数... 3.结合**all** = [通过*可以访问的模块]

import _ 表示可以使用模块里的所有内容,如果没有定义**all**所有的都可以访问
但是如果添加上了**all**,只有**all** = [''] 列表中可以访问
from user import _ 表示该包中内容(模块)是不能访问的,就需要在**init**.py 文件中定义**all** = [可通过*访问的模块]

循环导入:大型的 python 项目中,需要很多 python 文件,由于架构不当, 可能会出现模块之间相互导入
A:模块
def test():
f()
B:模块
def f():
test()
避免产生循环导入: 1.重新架构 2.将导入的语句放在函数里面 3.把导入的语句放在模块最后

sys.argv 查看启动 Python 程序时 附带的参数

time 模块:
time.time() 获取时间戳
time.sleep(2) 延时
time.ctime(t1) 将时间戳转为为时间格式
time.localtime(t) 将时间戳格式化为元组,可从中获取对应的时间信息
time.mktime(t) 将格式化 localtime 时间转化为时间戳
time.strftime('%Y-%m-%d %S:%M') 将元组的时间格式化成指定样式
time.strptime('2020/03/19 15:59', '%Y/%m/%d %S:%M') 字母转换成元组的方式

datetime 模块:  
 time 时间
date 日期 (date 数据)
datetime 日期时间 new()当前时间 str
timedalte 时间差 timedalta(days="",week="",hour="",...)

random 模块:
random.random() 0-1 之间小数
random.randint(a,b) a-b 之间的数字
random.randrange(start,end,step) 从 start 开始产生 end 随机数,以 step 为步长
random.choice([list]) 随机返回 List 列表内的元素
random.shuffle(list1) 打乱 list 列表内的数据顺序(修改原数组)
chr(random.randint(65, 90)) chr 将传入的数字转换为字母
ord('A') ord 将传入的内容转为 Unicode 码

hashlib 模块:(demo0320.py)
hashlib.md5(msg.encode('utf-8')) 将 Msg 编译成 md5
hashlib.sha1(msg.encode('utf-8')) 将 Msg 编译成 sha1

查看:
sha1 = hashlib.sha1(msg)
print(sha1.digest()) 查看编码
print(sha1.hexdigest()) 查看 16 进制编码

re 正则(demo0324.py)
re.match(reg,str) 进行正则字符串匹配第一次出现的结果
re.search()
re.findAll(reg,str) 进行正则全局匹配所有结果
re.sub(pattern,'新内容',string) 将匹配的数据进行替换
re.split(pattern,string ) 将符合的字符串位置切割成数组 result = re.split(r'[,:]', s3)
[a-z] 在正则中[]表示在括号中的任一数字

^开头
\$结尾
[] 范围

- 表示匹配 0 或者 0 以上(贪婪) >=0

* 表示匹配 1 或者 1 以上(贪婪) >=1
  ? 表示匹配 0 或者 1 次(贪婪) 1,0
  \*? +? ?? 非贪婪模式
  /s 空白
  /b 边界
  /d 数字
  /w word 字母
  (word|word|word) 区别 [163]表示是一个字母而不是一个单词
  {start,end} 表示匹配次数的范围
  在字符串之前加上 r'xxxx' 该字符串将不会发生转译

通过匹配正则中的小括号进行分组,使用 group(1) 获取分组数据
phone = '023-8848123'
result = re.match(r'(\d{3}|\d{4})-(\d{2,8})\$', phone)
print(result.group(1))
print(result.group(2))

s1 = '<html><head>hehehe</head></html>'
s2 = '<h1>ABC</h1>'
result = re.match(r'<[0-9a-zA-Z]+>(.+)</[0-9a-zA-Z]+>\$', s1)
print(result.group(1))

使用 (?P<名字>\w+) (?P=name) 为后期直接调用名字

进程与线程 (demo0325.py)
并发:当有多个线程在操作时,如果系统只有一个 CPU,则它根本不可能真正同时进行一个以上的线程,它只能把 CPU 运行的时间划分成若干个时间 段,在将时间段分配个各个线程执行,在一个时间段的线程代码运行时,其他线程处于挂起壮,
这种方式我们称之为并发(Concurrent)
并行:当系统有一个以上 CPU 时,则线程的操作有可能非并发。当一个 CPU 执行一个线程时,另一个 CPU 可以执行另一个线程,两个线程互不抢占 CPU 资源,可以同时进行,这种方式称之为并行。
多进程模式:
多线程模式:
协程:
进程>线程>协程

查看线程信息
import os  
os.getpid()查看子线程 id
os.getppid()查看主进程 id

from multiprocessing import Process

Process(target=函数,name= 进程的名字,args=(给函数传入的参数)
process 对象
自定义进程方法:
class myProcess(Process):
def run (self):

p = myProcess()
p.start()

对象调用方法:
process.start() 启动进程 并执行任务
process.run()只是执行任务 但是没启动进程、
terminate() 终止

当需要创建的子进程数量不多时,可以直接利用 multiprocessing 中的 Process 动态生成多个进程,
但是如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此事就可以用到 multiprocessing 模块提供的 Pool 方法,
初始化 Pool 时,可以指定一个最大进程数,当有新的请求提交到 Pool 中时,如果池还没满,
那么就会创建一个新的进程用来执行该请求:但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,
知道池中有进程结束,才会创建新的进程来执行。

poo = Pool(number) 创建进程池对象
初始 Pool(number) 时,新开启的进程将创建对应 number 数量的进程数进行交替使用

非阻塞式进程: 全部添加到队列中,按顺序进栈,执行完毕后立刻返回,直到队列清空 使用 pool.apply_async(func,args,callback)
阻塞式进程: 逐个调用队列中的线程,完成一个调用一个,没有返回值,知道队列清空 使用 pll.apply(func,args)

pool.close() 关闭
pool.join() 插队,让主进程让步,进行子进程的调用

队列方法(demo0326.py)
q = Queue(6)
q.full() 判断队列是否已满
q.empty() 判断队列是否已空
q.put(item) 推入队列
q.get() 获取队列数据

q.put_nowait() 不等待方法
q.get_nowait()

线程:有时被称为轻量进程,是程序执行流的最小单位。
多线程:是指从软件或硬件上实现懂个线程并发执行的技术。

t = threading.Thread(target=func,name = '',args = (a,))
t.start()
线程时可以共享全局变量的
Python 底层只要用线程默认加锁:
GIL 全局解释器锁
当线程异步处理统一数据是回出现数据不安全的情况,导致取得的数据出现问题
解决办法:线程同步,速度慢,数据安全

线程:适合耗时操作,爬虫,IO
进程:适合计算密集型

线程同步方法(demo0330.py)
from threading import Lock
l = Lock() 线程锁模块
l.acquire() 线程加锁 阻塞
l.release() 线程锁释放

数据共享
进程共享数据与线程共享数据区别:
进程是每个进程中都有一份数据
线程时所有并发线程公用一份数据 ==>数据安全性问题
GIL->伪线程  
 使用 Lock 模块添加及解除同步进程锁 lock.acquire() lock.release()
当使用加锁顺序不当时将出现死锁, 需避免死锁 timeout = number 或代码重构
线程间通信:生产者与消费者
生产者是一个线程
消费者也是一个线程
improt Queue
q = queue.Queue()

协程:微线程
进程>线程>协程
Process > Thread > 生成器完成

greenlet 手动协程模块
gevent 自动协程模块

gr = greenlet(func)
gr.switch() 指定下一个切换的函数

g = gevent.spawn(func,args)
g.join()
monkey 猴子补丁 from gevent import monkey monkey.patch_all() 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块

 

'
'
posted @ 2020-03-31 18:00  bomdeyada  阅读(207)  评论(0编辑  收藏  举报