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

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

前言

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


相关文章
|
2月前
|
安全 Linux 网络安全
Kali 渗透测试:基于结构化异常处理的渗透-使用Python编写渗透模块(一)
Kali 渗透测试:基于结构化异常处理的渗透-使用Python编写渗透模块(一)
71 2
|
2月前
|
Python Windows 网络安全
Kali 渗透测试:基于结构化异常处理的渗透-使用Python编写渗透模块(二)
Kali 渗透测试:基于结构化异常处理的渗透-使用Python编写渗透模块(二)
73 2
|
12天前
|
Python
[oeasy]python050_如何删除变量_del_delete_variable
本文介绍了Python中如何删除变量,通过`del`关键字实现。首先回顾了变量的声明与赋值,说明变量在声明前是不存在的,通过声明赋予其生命和初始值。使用`locals()`函数可查看当前作用域内的所有本地变量。进一步探讨了变量的生命周期,包括自然死亡(程序结束时自动释放)和手动删除(使用`del`关键字)。最后指出,删除后的变量将无法在当前作用域中被访问,并提供了相关示例代码及图像辅助理解。
106 68
|
14天前
|
Shell Python
[oeasy]python049_[词根溯源]locals_现在都定义了哪些变量
本文介绍了Python中`locals()`函数的使用方法及其在调试中的作用。通过回顾变量赋值、连等赋值、解包赋值等内容,文章详细解释了如何利用`locals()`函数查看当前作用域内的本地变量,并探讨了变量声明前后以及导入模块对本地变量的影响。最后,文章还涉及了一些与“local”相关的英语词汇,如`locate`、`allocate`等,帮助读者更好地理解“本地”概念在编程及日常生活中的应用。
27 9
|
17天前
|
缓存 监控 算法
Python内存管理:掌握对象的生命周期与垃圾回收机制####
本文深入探讨了Python中的内存管理机制,特别是对象的生命周期和垃圾回收过程。通过理解引用计数、标记-清除及分代收集等核心概念,帮助开发者优化程序性能,避免内存泄漏。 ####
29 3
|
26天前
|
Python
Python三引号用法与变量详解
本文详细介绍了Python中三引号(`"""` 或 `'''`)的用法,包括其基本功能、如何在多行字符串中使用变量(如f-string、str.format()和%操作符),以及实际应用示例,帮助读者更好地理解和运用这一强大工具。
43 2
|
1月前
|
UED 开发者 Python
Python中的异常处理机制
Python中的异常处理机制
39 2
|
1月前
|
人工智能 Python
[oeasy]python039_for循环_循环遍历_循环变量
本文回顾了上一次的内容,介绍了小写和大写字母的序号范围,并通过 `range` 函数生成了 `for` 循环。重点讲解了 `range(start, stop)` 的使用方法,解释了为什么不会输出 `stop` 值,并通过示例展示了如何遍历小写和大写字母的序号。最后总结了 `range` 函数的结构和 `for` 循环的使用技巧。
35 4
|
2月前
|
Python
【10月更文挑战第5天】「Mac上学Python 8」基础篇2 - 变量深入详解
本篇将详细介绍Python中变量的使用方式和进阶操作,涵盖变量的输入与输出、变量的多重赋值、变量的内存地址管理以及变量的传递和交换等操作。通过本篇的学习,用户将对变量的使用有更深入的理解,并能灵活运用变量进行各种编程操作。
55 1
【10月更文挑战第5天】「Mac上学Python 8」基础篇2 - 变量深入详解
|
29天前
|
机器学习/深度学习 存储 数据挖掘
Python 编程入门:理解变量、数据类型和基本运算
【10月更文挑战第43天】在编程的海洋中,Python是一艘易于驾驭的小船。本文将带你启航,探索Python编程的基础:变量的声明与使用、丰富的数据类型以及如何通过基本运算符来操作它们。我们将从浅显易懂的例子出发,逐步深入到代码示例,确保即使是零基础的读者也能跟上步伐。准备好了吗?让我们开始吧!
26 0
下一篇
DataWorks