Python内存泄漏的原因
1、C语言开发的底层模块中出现了内存泄露
2、代码中用到了全局的 list、 dict 或其它容器,不停的往这些容器中插入对象,而忘记了在使用完之后进行删除回收
3、代码中有循环引用
Python零散知识点
- 对象动态属性、类动态属性
- 函数传参,不可变数据类型为值传递,可变数据类型为引用传递
- 类名定义:首字母大写 ;其他遵循驼峰原则、见名知意
- sys.stdout.flush()
print默认时以‘\n’结尾,刷新缓冲然后输出。如果没有换行符就会等到程序结束才输出。
Python – sys.stdout.flush()
import time
import sys
for i in range(5):
print(i,end="")
sys.stdout.flush()
time.sleep(1)
- 新式类(区别经典类)
在Python3.x中,如果没有显示指明要继承的父类,则默认继承object类 - 下划线
__ xx __ 魔法函数
_ xx 只能被模块内部使用,无法通过from my_module import * 导入
xx_ 想用python关键字,又不想语法错误,如pass,可以pass_
__xx 类的私有属性,不能外部调用,不能被子类重写 - 容器模块collections(defaultdict与dict类型不同,不需要检查key是否存在;Counter计数器,可以针对某项数据进行计数;deque双端队列,可以从头/尾两端添加或删除元素;namedtuples像字典(dict)一样访问,但namedtuples是不可变的;枚举对象enum.Enum)
- Python3的解释器以"UTF-8"作为默认编码,但是这并不表示可以完全兼容中文问题。比如我们在Windows上进行开发时,Python工程及代码文件都使用的是默认的GBK编码,也就是说Python代码文件是被转换成GBK格式的字节码保存到磁盘中的。
- 字符串类型分别为 str 和 bytes 两种,其中 str 用来表示 Unicode 字符,bytes 用来表示二进制数据。str 类型和 bytes 类型之间就需要使用 encode() 和 decode() 方法进行转换。
- 在内存中读写,字符串使用StringIO,bytes使用BytesIO。
from io import BytesIO
byIo = BytesIO()
#参数类型为bytes
byIo.write("我的byio".encode("utf-8"))
#通过内存写入文件
with open("file.txt",mode="wb") as file:
file.write(byIo.getvalue())
- 虚拟环境Virtualenv 是一个工具,它能够为不同项目创建一个独立(隔离)的Python环境,而不是在全局安装所依赖的模块。
- datatime模块重新封装了time模块,提供更多接口,提供的类有:date,time,datetime,timedelta,tzinfo。
- is 判断是否是一个ID, == 判断内容是否一致。
- 统计列表中元素的频率
from collections import Counter
numbers = [1, 1, 3, 2, 4, 4, 3, 6]
# 一行代码搞定求列表中每个元素出现的频率
count = Counter(numbers)
print(count)
输出:
Counter({1: 2, 3: 2, 4: 2, 2: 1, 6: 1})
- __iter__方法、__getitem__方法(支持下标索引)都能产生可迭代对象
__getitem__单独实现该函数,可以让这个类成为一个可迭代的对象,并且可以通过使用下标获取类中元素值下标的元素
__call __实现该函数后,可通过类名直接调用该函数
【Python】__iter__和__getitem__区别 - 元类
- 魔法函数(特殊方法)
- 内置函数、匿名函数(lambda表达式)
- 单例模式
- 生成器、迭代器
- 反射/自省
通过hasattr、getattr、setattr、delattr四个内置函数实现的,其实这四个内置函数不只可以用在类和对象中,也可以用在模块等其他地方,只是在类和对象中用的很多 - 列表、集合、字典生成式(推导式、解析式)
列表生成式直接生成一个多元素列表
元组会生成迭代器
高阶函数(函数可作为参数、返回值可以是函数)
map(),filter(), reduce() ,sorted()
其中reduce函数在 python 2 是内置函数, 从python 3 开始移到了 functools 模块。
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) 计算方式((((1+2)+3)+4)+5).
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
集合set()
|并集、union
语法:set1 | set2 或者set1.union(set2)返回所有集合的元素,重复的元素只会出现一次
alpha_set = {'c', 'b'}
num_set = {1,2,'b'}
print(alpha_set | num_set)
print(num_set.union(alpha_set))
{1, 2, 'c', 'b'}
{1, 2, 'c', 'b'}
&交集、intersection
语法:set1 & set2orset1.union(set2)返回两个或更多集合中都包含的元素,即交集
alpha_set = {'c', 'b'}
num_set = {1,2,'b'}
print(alpha_set & num_set)
print(num_set.intersection(alpha_set))
{'b'}
{'b'}
-差集、difference
语法:set1 - set2orset1.difference(set2)返回的集合元素包含在set1中,但不包含在set2中
alpha_set = {'c', 'b'}
num_set = {1,2,'b'}
print(alpha_set - num_set)
print(num_set.difference(alpha_set))
{'c'}
{1, 2}
^对称差集、symmetric_difference
语法:set1 ^ set2orset1.symmetric_difference(set2)返回两个集合中不重复的元素集合
alpha_set = {'c', 'b'}
num_set = {1,2,'b'}
print(alpha_set ^ num_set)
print(num_set.symmetric_difference(alpha_set))
{'c', 1, 2}
{'c', 1, 2}
==
语法:set1 == set2判断两个集合是否相同
alpha_set = {'c', 'b'}
num_set = {1,2,'b'}
print(alpha_set == num_set)
False
父集:>、>= 、issuperset
语法:set1 > set2orset1 >= set2or set1.issuperset(set2)判断set1是否包含set2
alpha_set = {'c', 'b',1,2}
num_set = {1,2,'b'}
num_set1 = {1,'b',2}
print(alpha_set > num_set)
print(num_set.issuperset(num_set1)) # issuperset相当于 >=
print(num_set > num_set1)
True
True
False
子集:<、<= 、issubset
语法:set1 < set2orset1 <= set2or set1.issubset(set2)判断set2是否包含set1
alpha_set = {'c', 'b',1,2}
num_set = {1,2,'b'}
num_set1 = {1,'b',2}
print(num_set < alpha_set)
print(num_set.issubset(num_set1)) # issubset相当于 <=
print(num_set < num_set1)
True
True
False
深拷贝、浅拷贝
在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。
(1)直接赋值,默认浅拷贝传递对象的引用而已,原始列表改变,被赋值的也会做相同的改变
(2)浅拷贝,没有拷贝对象里面的子对象(列表中的列表),所以原始数据子对象改变,深拷贝里子对象也会改变
(3)深拷贝,包含对象里面的子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
上面例子中说的是列表(可变对象)的拷贝,那对于元组,字符等不可不对象呢?
答案是,对不可变对象,其实不存在深浅拷贝的问题。无论怎么拷贝,效果都是新建立一个指向不可变对象的指针而已。
Python中的赋值(复制)、浅拷贝与深拷贝
修饰器
赋予一个函数其他的功能,但又不去改变函数自身。把多个函数共性的东西抽取出来。修饰器本质是一个函数,该函数的输入输出都是函数。
1、被调函数加参数
2、修饰器加参数(再包一层函数)
3、修饰器类
内置修饰器property、 staticmethod、 classmethod,他们有个共同点,都是作用于类方法之上
闭包(区别嵌套函数)
当一个函数定义在另一个函数内,且使用到了外部函数的参数。整个代码块称为闭包。
如何创建闭包?需要满足下面三点:
1、闭包函数必须有内嵌函数
2、内嵌函数需要引用该嵌套函数上一级中的变量
3、闭包函数必须返回内嵌函数
闭包可以避免使用全局值,并提供某种形式的数据隐藏
python基础(三)内嵌函数与闭包
- 从函数中返回函数
多线程、多进程
0、Python标准库自带了两个多线程模块,分别是threading和thread,其中,thread是低级模块,threading是对thread的封装
1、父子进程会独立运行,互不干扰。而且父子进程的调用需要系统来调度。
2、默认情况下,python产生的线程是非守护线程( setDaemon(False))即主线程不会等待子线程完成任务,而是异步执行程序,把任务交给子线程之后,主线程继续往下执行,遇到新的任务后,主线程可以选择自己执行,也可以再次产生新的子线程去执行,当主线程执行完所有的程序后,这个时候主线程并不会退出,也就是不会销毁,直到所有的子线程完成了各自的任务后才自动销毁。
3、守护线程 (setDaemon(True))即主线程一旦结束,就会退出,也就是自动销毁,不会等待子线程,主线程一旦销毁,则所有的子线程也会跟着销毁,无论任务是否执行完成。
4、同步线程(join)当主线程遇到同步线程的时候,即遇到join()的时候会等待(即主线程进入堵塞状态,无法继续前行)所有的同步线程执行完毕之后,主线程才继续往下走,这里说的同步是针对主线程而言,意思是遇到join的时候,主线程会被堵塞,不会继续往下执行其它程序,而是等待join的线程执行完毕后再往下执行,而多个join的子线程之间是并行的,即互不影响。
5、互斥锁,多个线程共同对某个数据修改,为了保证数据的正确性,需要使用互斥锁对多个线程进行同步,限制当一个线程正在访问数据时,其他只能等待,直到前一线程释放锁。对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。也可以使用with lock。
进程与线程
线程池、进程池
1、由于线程预先被创建并放入线程池中,同时处理完当前任务之后并不销毁而是被安排处理下一个任务,因此能够避免多次创建线程,从而节省线程创建和销毁的开销,能带来更好的性能和系统稳定性。
2、 ThreadPoolExecutor 用于创建线程池,而 ProcessPoolExecutor 用于创建进程池。
3、如果使用线程池/进程池来管理并发编程,那么只要将相应的 task 函数提交给线程池/进程池,剩下的事情就由线程池/进程池来搞定。程序将 task 函数提交(submit)给线程池后,submit 方法会返回一个 Future 对象,Future 类主要用于获取线程任务函数的返回值。由于线程任务会在新线程中以异步方式执行,因此,线程执行的函数相当于一个“将来完成”的任务,所以 Python 使用 Future 来代表。
- 返回子进程的结果:多进程共享全局变量之Manager()、进程通信
python加速PyPy、Numba 、Cython、Pyjion
优化 Python 性能:PyPy、Numba 与 Cython,谁才是目前最优秀的 Python 运算解决方案?
Cython基本用法
用Cython加速Python到“起飞”
java、c/c++ 、python 等性能比较 杂谈(整理)
pypy真的能让python比c还快?
numba从入门到精通(1)—为什么numba能够加速
用Cython和PyPy提升Python性能
python性能优化的比较:numba,pypy, cython
java为什么比python快
微软发布 Python 的 JIT 编译器:Pyjion 文末包邮送新书
A drop-in JIT Compiler for Python 3.10
win10 + pypy3解释器的的安装及配置 以及第三方库的安装
Python调用c代码ctypes、swig、cython、pybind11
如果遇到需要 Python C/C++ 混合编程的需求,尽量使用 Pybind11 或 Cython,ctypes 和 Python-C-API 方案尽量不考虑。
Pybind11
python加密
python打包
- auto-py-to-exe
- Pyinstaller
python 可视化打包exe,这个打包神器绝了
Python打包exe的王炸-Nuitka - Nuitka 经测试,Nuitka打包后的exe比Pyinstaller打包后的exe运行速度提升30%,PyQT5的UI文件转换成py文件转换成C语言后,界面秒开呀。