1.引用计数机制
python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。
- python里每一个东西都是对象,它们的核心就是一个结构体:PyObject。
- PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的obrefcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。
- 当引用计数为0时,该对象生命就结束了。
- PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的obrefcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。
- 引用计数的优点:
- 简单、实时性(一旦没有引用,内存就直接释放了。不用像其他机制需要等到特定时机,处理回收内存的时间分摊到了平时)。
- 引用计数的缺点:
- 1.维护引用计数会消耗资源
- 2.
list1 = [] list2 = [] list1.append(list2) list2.append(list1)
- list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。循环引用导致内存泄露,注定python还将引入新的回收机制。(标记清除和分代收集)
- GC负责的主要任务:
- 1.为新生成的对象分配内存
- 2.识别那些垃圾对象
- 3.从垃圾对象那回收内存。
- list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。循环引用导致内存泄露,注定python还将引入新的回收机制。(标记清除和分代收集)
2.Python中的循环数据结构及引用计数
3.Python中的GC模块---自动调用(阈值)、手动调用
Python 垃圾回收机制: Python中的垃圾回收是以引用计数为主,分代收集为辅。
导致引用计数+1的情况:
导致引用计数-1的情况:
查看一个对象的引用计数:
import sys
a = "hello world"
sys.getrefcount(a)
可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1。
内存泄漏:申请了某些内存,但是忘记了释放,那么这就造成了内存的浪费,久而久之内存就不够用了。
手动调用gc回收垃圾
class ClassA():
def __init__(self):
print('id = %s'%str(id(self)))
def f2():
while True:
c1 = ClassA()
c2 = ClassA()
c1.t = c2
c2.t = c1
del c1
del c2
gc.collect()#手动调用垃圾回收功能,这样在自动垃圾回收被关闭的情况下,也会进行回收
#python默认是开启垃圾回收的,可以通过下面代码来将其关闭
gc.disable()
f2()
有三种情况会触发垃圾回收:
4.Python 内存优化-----小整数池和大整数池
- Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。
- Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。
大整数池和小整数池的区别:
1. 从结果上看是一样的;
2. 大整数池没有提前创建好对象,是一个空池子,需要我们自己去创建,创建好之后,会把整数对象保存到池子里面,后面不需要再创建了,直接拿来使用即可;
3.小整数池是提前将【-5,256】的数据都提前创建好。
5.Python pep8规范
- 缩进:使用Tab或者四个空格;只能用一种。
- 行宽:每行最大长度79,换行可以使用反斜杠,最好使用圆括号。换行点要在操作符的后边敲回车。 文本长块,比如文档字符串或注释,行长度应限制为72个字符。
- 空行:
1. 类和 top-level 函数定义之间空两行2. 类中的方法定义之间空一行3. 函数内逻辑无关段落之间空一行4.其他地方尽量不要再空行
- 源代码编码
- 模块导入
# 导入始终在文件的顶部,在模块注释和文档字符串之后,在模块全局变量和常量之前。
# 不同模块分行导入,内置模块放在前面,第三方模块在在后面导入
import os
import sys
from subprocess import Popen, PIPE
# 不建议使用这种方式导入,因为它不清楚命名空间有哪些名称存,混淆读者和许多自动化的工具。
from xxx import *
- 表达式和语句中空格的使用
- 注释
- 命名规范
6.Python 命令行参数(运维、脚本)参数
在使用python开发脚本,作为一个运维工具,或者其他工具需要接受用户参数运行时,这里就可以用到命令行传参的方式,可以给使用者提供一个比较友好的交互体验。
sys模块
(1)python可以sys模块中的sys.args来获取命令行参数
import sys
print('参数个数为:', len(sys.argv), '个参数。')
print('参数列表:', str(sys.argv))
#可以在python的terminal中运行命令行,输入:
python test.py #红色部分全部都是参数
#输出:参数个数为: 1 个参数
# 参数列表: ['test.py']
python test.py 1 2 3
#输出:参数个数为: 4 个参数
# 参数列表: ['test.py', '1', '2', '3']
(2)argv 返回命令行参数是一个列表,第一个元素就是 .py文件的文件名。如果只想获取参数不需要获取文件名,sys.argv也支持python字符串中的切片。修改代码如下:
import sys
print('参数个数为:', len(sys.argv), '个参数。')
print('参数列表:', str(sys.argv[1:]))
# 再termina中输入:
python3 test.py 1 2 3
#输出: 参数个数为: 3 个参数。
# 参数列表: ['1', '2', '3']
sys.argv 只提供了比较简单的命令参数获取方式,并没有提供命令提示。无法做到像linux命令一样,可以给使用者提供help帮助。
argparse模块
(1)argparse 模块可以轻松编写用户友好的命令行界面。该程序定义了它需要的参数,argparse 并将找出如何解析这些参数sys.argv。该argparse 模块还会自动生成帮助和用法消息,并在用户给出程序无效参数时发出错误
import argparse
parser = argparse.ArgumentParser(prog='my - program', usage='%(prog)s [options] usage',description = 'my - description',epilog = 'my - epilog')
print(parser.print_help())
#再terminal里输入:
python3 test.py
#输出:
usage: my - program [options] usage
my - description
optional arguments:
-h, --help show this help message and exit
my - epilogNone
参数说明:
- prog :文件名,默认为sys.argv[0],用来在help信息中描述程序的名称。
- usage :描述程序用途的字符串
- description :help信息前显示的信息
- epilog :help信息之后显示的信息
(2)添加参数选项-add argument()
ArgumentParser.add_argument(name or flags...[, action][, nargs][, const]
[, default][, type][, choices][, required]
[, help][, metavar][, dest]
)
#metaver:帮助信息中显示的参数名称
#const :保存一个常量
#default :默认值
#type :参数类型,默认为str
#choices :设置参数值的范围,如果choices中的类型不是字符串,记得指定type
#required :该选项是否必选,默认为True
#dest :参数名
- name or flags :参数有两种,可选参数和位置参数。
- 添加可选参数: parser.add_argument('-f', '--foo')
- 添加位置参数: parser.add_argument('bar')
- parse_args()运行时,默认会用’-‘来认证可选参数,剩下的即为位置参数, 位置参数必须传。
例:
可以将输出的元组中的元素分开输出
课后练习:实现 命令行登录系统【如masql登录 mysql -u root -r 111111】
可选参数【-u 和 -r】:
如果给出-u ,必须给出用户名!(蓝色)
如果给出-r,必须给出密码!(蓝色)
没有给出-u和-r可以不给用户名和密码。(红色)