系列文章目录
- Python数据类型:编程新手的必修课
- 深入探索Python字符串:技巧、方法与实战
- Python 函数基础详解
- Python正则表达式详解:掌握文本匹配的魔法
- Python文件操作宝典:一步步教你玩转文件读写
- Python面向对象基础与魔法方法详解
- Python面向对象进阶:深入解析面向对象三要素——封装、继承与多态
- Python进阶之旅:深入理解变量作用域、垃圾回收、拷贝机制与异常处理
- Python函数进阶:四大高阶函数、匿名函数、枚举、拉链与递归详解
- 从零开始学迭代器生成器:打造高效、易读的Python代码
- Python进阶:深入剖析闭包与装饰器的应用与技巧
- PyMySQL:连接Python与MySQL的桥梁
文章目录
前言
在Python编程的进阶道路上,理解变量作用域、垃圾回收、拷贝机制与异常处理至关重要。本文将深入探讨这些核心概念,助你编写更健壮、高效的代码。从变量作用域到内存管理,再到数据拷贝与异常捕获,让我们一同揭开Python编程的深层奥秘。
一、变量的作用域
1.命名空间
内置命名空间 — python解释器范围下
全局命名空间 — py文件下
局部命名空间 — 函数或类下
2.作用域
内置作用域 校长
全局作用域 年级主任
嵌套作用域 班主任
局部作用域 讲师
# 全局作用域下的变量:全局变量
a = 10
def func():
# 嵌套作用域下的变量
c = 30
def func1():
# 局部作用域下的变量:局部变量
b = 20
def、class、lambda 是可以引入新作用域的
3.LEGB法则
LEGB:作用域的查询顺序(就近原则)
内置作用域 built-in B
全局作用域 Global G
嵌套作用域 Enclosed E
局部作用域 Local L
局部-->嵌套-->全局-->内置
# 全局作用域下的变量:全局变量
a = 10
def func():
# 嵌套作用域下的变量
a = 30
def func1():
# 局部作用域下的变量:局部变量
a = 20
print(a)
func1()
func()
4.修改全局变量
a = 10
def func():
# 修改全局变量的值--》不可变数据类型
# global 要修改的全局变量的变量名
# 换行对变量进行重新赋值
global a
a = 20
print(a)
func()
print(a)
5.修改嵌套作用域下的变量
def outer():
a = 10
def inner():
# 修改嵌套作用域下的变量 nonlocal
# nonlocal 要修改的嵌套作用域下的变量名
# 换行给变量重新赋值
nonlocal a
a += 1
print(a)
inner()
print(a)
outer()
二、python垃圾回收机制
1. 引用计数
每一个对象会维护一个ob_ref表,表中存放当前对象的被引用次数;
当对象的被引用次数为0,当前对象会被作为垃圾进行收回
import sys
# 引用计数
# 获取对象的被引用次数
print(sys.getrefcount(1))
# 引用计数+1
a = 1
b = a
lst = [1,2,3,4]
# 引用计数-1
b = 2
del a
print(sys.getrefcount(1))
2. 标记清除
跟其名称一样,该算法在进行垃圾回收时分成了两步,分别是:
- A)标记阶段,遍历所有的对象,如果是可达的(reachable),也就是还有对象引用它,那么就标记该对象为可达;
- B)清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收。
缺陷:在执行标记清除过程中,会将其他正在执行的程序进行终止。会使得资源利用率极低
3.分代回收
它将内存中的对象按生存期划分为几个不同的"代",每次只对某一代进行回收,
优点:减少垃圾回收的次数,提高垃圾回收的效率。
它将内存中的对象分为三种:新生代、老年代和永久代。
新生代只包括新创建的对象;
老年代是存放比较“老”的对象,也就是存活比较久的对象;
永久代则存放三种物件:模块、类和常量。
三、深浅拷贝
1. is 和 ==
# is和 ==
# a == b:判断a和b的值是否相等;如果相等则返回True,否则返回False
# a is b:判断a和b是否是同一个数据;
# 获取对象的内容地址 id(数据)
# 指向关系:整型、浮点型、字符串、元组 (不可变)
a = {"name":"张三"}
b = {"name":"张三"}
print(id(a))
print(id(b))
print(a == b)
print(a is b)
2.浅拷贝
import copy
# 拷贝模块 copy
# 浅拷贝 需要使用copy模块中copy方法
# 结论:浅拷贝只拷贝第一层,深层次的数据改变都会影响其他.
# 拷贝不可变数据类型的数据--》不可变数据类型永远指向关系
a = (1,2,3)
b = copy.copy(a)
print(id(a),id(b))
print(a is b)
# 拷贝可变数据类型的数据
list1 = [1,2,3,[4,5,6]]
list2 = copy.copy(list1)
# 获取整个数据的id,浅拷贝后的数据id不同
print(id(list1),id(list2))
print(list1 is list2)
# 查询拷贝前后深层次数据是否是同一个
print(id(list1[3]),id(list2[3]))
print(list1[3] is list2[3])
# 修改原数据中浅层数据,拷贝后的数据不会发生变化
list1.append(7)
print(list1)
print(list2)
# 修改原数据中深层数据,拷贝后的数据会随之发生变化
list1[3].append(8)
print(list1)
print(list2)
3.深拷贝
import copy
# 深拷贝 需要使用copy模块deepcopy
# 结论:深拷贝是完全拷贝,数据变化只影响自己本身
# 拷贝不可变数据类型--》不可变数据类型永远都是指向关系
a = ("hello",)
b = copy.deepcopy(a)
print(id(a),id(b))
print(a is b)
# 拷贝可变数据类型
list1 = [1,2,3,[4,5,6]]
list2 = copy.deepcopy(list1)
# 获取整个数据的id,拷贝后的数据id不同
print(id(list1),id(list2))
print(list1 is list2)
# 查询拷贝前后深层次数据是同一个
print(id(list1[3]),id(list2[3]))
print(list1[3] is list2[3])
# 对原数据的浅层数据进行操作,拷贝后的数据不会发生变化
list1.append(7)
print(list1)
print(list2)
# 对原数据的深层数据进行操作,拷贝后数据不会发生变化
list1[3].append(8)
print(list1)
print(list2)
4.深浅拷贝的区别
浅拷贝:只拷贝第一层数据,深层数据还是指向关系
深拷贝:完全拷贝,拷贝前后的数据没有关系
四、异常处理
1.简单异常处理
# 简单异常处理
# try:
# 存放可能会出现问题的代码
# except 异常类型:
# 如果真的出现这个异常,则执行except中的代码
list1 = [1,2,3]
try:
print(list1[20])
except IndexError:
print("好好数数你的索引!!!!")
2.处理多种异常
2.1 第一种方式
# try:
# 存放可能会出现问题的代码
# except 异常类型:
# 如果真的出现这个异常,则执行except中的代码
# except 异常类型:
# 如果真的出现这个异常,则执行except中的代码
list1 = [1,2,3]
try:
print(list2[20])
except IndexError:
print("好好数数你的索引!!!!")
except NameError:
print("瞧瞧你的变量名~")
2.2 第二种方法
# try:
# 存放可能会出现问题的代码
# except (异常类型1,异常类型2):
# 如果真的出现这个异常,则执行except中的代码
list1 = [1,2,3]
try:
print(list1[20])
except (IndexError,NameError):
print("好好看看你的变量")
2.3 第三种方式
# try:
# 存放可能会出现问题的代码
# except:
# 如果真的出现异常,则执行except中的代码
list1 = [1,2,3]
try:
list1.add(4)
print(list2[20])
except:
print("好好看看你的变量")
3.获取异常信息
3.1 单个异常
# 获取错误信息
# 异常类型 as 变量:将出现当前异常的错误信息赋值给变量
list1 = [1,2,3]
try:
print(list1[20])
except IndexError as e:
print(e)
3.2 多个异常
# 获取错误信息
# 异常类型 as 变量:将出现当前异常的错误信息赋值给变量
list1 = [1,2,3]
try:
print(list1[20])
except (IndexError,NameError) as e:
print(e)
4.万能异常处理
# Exception:所有常规异常的基类,包含所有的常规异常
# try:
# 存放可能会出现问题的代码
# except Exception as e:
# print(e)
# 如果真的出现异常,则执行except中的代码;e接收所有的错误信息
list1 = [1,2,3]
try:
list1.add(4)
print(list1[20])
except Exception as e:
print(e)
5.else
# try:
# 可能会出现问题的代码
# except Exception as e:
# 如果真的出现异常则执行except中的代码块
# else:
# 如果代码没有出现异常则执行else中的代码块
list1 = [1,2,3]
try:
print(list1[20])
except Exception as e:
print(e)
else:
print("嘿嘿嘿嘿嘿嘿")
6.finally
# finally-->可以只与try搭配使用
# try:
# 可能会出现问题的代码
# except Exception as e:
# 如果代码出现问题则执行except中的代码块
# else:
# 如果代码没有问题则执行else中的代码块
# finally:
# 无论代码是否出现问题最终都会执行finally中的代码块
list1 = [1,2,3]
try:
print(list1[2])
except Exception as e:
print(e)
print("这是except中的代码")
else:
print("这是else中的代码")
finally:
print("这是finally中的代码")
7.自定义异常
class MyCls:
def __init__(self,s):
self.s = s
def a(self,a,b):
try:
return a/b
except Exception as e:
if self.s == True:
print(e)
else:
# 将原本需要抛出的异常进行抛出
# raise 异常类型 -->在程序中raise 后面的异常类型可以不指定
raise
my = MyCls(True)
print(my.a(10,0))