12. python垃圾回收机制

1.引用计数机制

python采用的是引用计数机制为主,标记-清除分代收集两种机制为辅的策略。

  •         python里每一个东西都是对象,它们的核心就是一个结构体:PyObject。
    •         PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的obrefcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。
      •         当引用计数为0时,该对象生命就结束了。
  • 引用计数的优点:
  • 简单、实时性(一旦没有引用,内存就直接释放了。不用像其他机制需要等到特定时机,处理回收内存的时间分摊到了平时)。
  • 引用计数的缺点:
  • 1.维护引用计数会消耗资源 
  • 2.
    list1 = []
    list2 = []
    list1.append(list2)
    list2.append(list1)
    •        list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。循环引用导致内存泄露,注定python还将引入新的回收机制。(标记清除和分代收集)
      • GC负责的主要任务:
      • 1.为新生成的对象分配内存
      • 2.识别那些垃圾对象
      • 3.从垃圾对象那回收内存。 

2.Python中的循环数据结构及引用计数

3.Python中的GC模块---自动调用(阈值)、手动调用

Python 垃圾回收机制: Python中的垃圾回收是以引用计数为主,分代收集为辅。

导致引用计数+1的情况:

1. 对象被创建
2. 对象被引用
3. 对象被作为参数,传入到一个函数中
4. 对象作为一个元素,存储在容器中

导致引用计数-1的情况:

1. 对象的别名被显式销毁
2. 对象的别名被赋予新的对象
3. 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
4. 对象所在的容器被销毁,或从容器中删除对象

查看一个对象的引用计数: 

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()

有三种情况会触发垃圾回收:

1. 当gc模块的计数器达到阀值的时候,自动回收垃圾
2. 调用gc.collect(),手动回收垃圾
3. 程序退出的时候,python解释器来回收垃圾

4.Python 内存优化-----小整数池和大整数池

  • Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。
  • Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。

大整数池和小整数池的区别:

1. 从结果上看是一样的;

2. 大整数池没有提前创建好对象,是一个空池子,需要我们自己去创建,创建好之后,会把整数对象保存到池子里面,后面不需要再创建了,直接拿来使用即可;

3.小整数池是提前将【-5256】的数据都提前创建好。

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描述程序用途的字符串
  • descriptionhelp信息前显示的信息
  • epiloghelp信息之后显示的信息

(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可以不给用户名和密码。(红色) 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值