当前位置:   article > 正文

Python进阶之旅:深入理解变量作用域、垃圾回收、拷贝机制与异常处理

Python进阶之旅:深入理解变量作用域、垃圾回收、拷贝机制与异常处理

在这里插入图片描述

系列文章目录

  1. Python数据类型:编程新手的必修课
  2. 深入探索Python字符串:技巧、方法与实战
  3. Python 函数基础详解
  4. Python正则表达式详解:掌握文本匹配的魔法
  5. Python文件操作宝典:一步步教你玩转文件读写
  6. Python面向对象基础与魔法方法详解
  7. Python面向对象进阶:深入解析面向对象三要素——封装、继承与多态
  8. Python进阶之旅:深入理解变量作用域、垃圾回收、拷贝机制与异常处理
  9. Python函数进阶:四大高阶函数、匿名函数、枚举、拉链与递归详解
  10. 从零开始学迭代器生成器:打造高效、易读的Python代码
  11. Python进阶:深入剖析闭包与装饰器的应用与技巧


前言

    在Python编程的进阶道路上,理解变量作用域、垃圾回收、拷贝机制与异常处理至关重要。本文将深入探讨这些核心概念,助你编写更健壮、高效的代码。从变量作用域到内存管理,再到数据拷贝与异常捕获,让我们一同揭开Python编程的深层奥秘。


一、变量的作用域

1.命名空间

内置命名空间 — python解释器范围下
全局命名空间 — py文件下
局部命名空间 — 函数或类下

2.作用域

内置作用域    校长 
全局作用域    年级主任
嵌套作用域    班主任
局部作用域    讲师

# 全局作用域下的变量:全局变量
a = 10

def func():
    # 嵌套作用域下的变量
    c = 30
    def func1():
        # 局部作用域下的变量:局部变量
        b = 20


defclasslambda 是可以引入新作用域的
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

4.修改全局变量

a = 10
def func():
    # 修改全局变量的值--》不可变数据类型
    # global 要修改的全局变量的变量名
    # 换行对变量进行重新赋值
    global a
    a = 20
    print(a)

func()
print(a)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

5.修改嵌套作用域下的变量

def outer():
    a = 10
    def inner():
        # 修改嵌套作用域下的变量  nonlocal
        # nonlocal 要修改的嵌套作用域下的变量名
        # 换行给变量重新赋值
        nonlocal a
        a += 1
        print(a)
    inner()
    print(a)
outer()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

二、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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

2. 标记清除

跟其名称一样,该算法在进行垃圾回收时分成了两步,分别是:

- A)标记阶段,遍历所有的对象,如果是可达的(reachable),也就是还有对象引用它,那么就标记该对象为可达;
- B)清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收。

缺陷:在执行标记清除过程中,会将其他正在执行的程序进行终止。会使得资源利用率极低
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.分代回收

它将内存中的对象按生存期划分为几个不同的"代",每次只对某一代进行回收,
优点:减少垃圾回收的次数,提高垃圾回收的效率。
它将内存中的对象分为三种:新生代、老年代和永久代。
	新生代只包括新创建的对象;
	老年代是存放比较“老”的对象,也就是存活比较久的对象;
	永久代则存放三种物件:模块、类和常量。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

三、深浅拷贝

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

4.深浅拷贝的区别

浅拷贝:只拷贝第一层数据,深层数据还是指向关系
深拷贝:完全拷贝,拷贝前后的数据没有关系


四、异常处理

1.简单异常处理

# 简单异常处理
# try:
#     存放可能会出现问题的代码
# except 异常类型:
#     如果真的出现这个异常,则执行except中的代码

list1 = [1,2,3]
try:
    print(list1[20])
except IndexError:
    print("好好数数你的索引!!!!")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2.处理多种异常

2.1 第一种方式

# try:
#     存放可能会出现问题的代码
# except 异常类型:
#     如果真的出现这个异常,则执行except中的代码
# except 异常类型:
#     如果真的出现这个异常,则执行except中的代码

list1 = [1,2,3]
try:
    print(list2[20])
except IndexError:
    print("好好数数你的索引!!!!")
except NameError:
    print("瞧瞧你的变量名~")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2.2 第二种方法


# try:
#     存放可能会出现问题的代码
# except (异常类型1,异常类型2):
#     如果真的出现这个异常,则执行except中的代码


list1 = [1,2,3]
try:
    print(list1[20])
except (IndexError,NameError):
    print("好好看看你的变量")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.3 第三种方式

# try:
#     存放可能会出现问题的代码
# except:
#     如果真的出现异常,则执行except中的代码


list1 = [1,2,3]
try:
    list1.add(4)
    print(list2[20])
except:
    print("好好看看你的变量")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3.获取异常信息

3.1 单个异常

# 获取错误信息
# 异常类型 as 变量:将出现当前异常的错误信息赋值给变量

list1 = [1,2,3]
try:
    print(list1[20])
except IndexError as e:
    print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.2 多个异常

# 获取错误信息
# 异常类型 as 变量:将出现当前异常的错误信息赋值给变量

list1 = [1,2,3]
try:
    print(list1[20])
except (IndexError,NameError) as e:
    print(e)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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("嘿嘿嘿嘿嘿嘿")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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中的代码")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/616596
推荐阅读
相关标签
  

闽ICP备14008679号