Python高级用法 #GIL #拷贝 #私有化 #MRO #类 #实例对象 #with与上下文管理器

一、全局解释器锁GIL

  • GIL全局解释器锁

1.1查看资源占用

  • 输入htop

在这里插入图片描述

1.2单线程死循环

请用虚拟机运行

while True:
    pass
  • 会发现一个核占满了
  • 再在另一个终端里,运行同一个文件,会发现。两个核都占满了。

1.3多线程死循环

请用虚拟机运行

import threading

# 子线程死循环
def test():
    while True:
        pass


t1 = threading.Thread(target=test)
t1.start()

# 主线程死循环
while True:
    pass
  • 会发现两个核都没满,但是两个核的占用率之和为100%

1.4多进程死循环

请用虚拟机运行

import multiprocessing

# 子进程死循环
def test():
    while True:
        pass


p1 = multiprocessing.Process(target=test)
p1.start()

# 主进程死循环
while True:
    pass
  • 会发现两个核占满了

1.5GIL全局解释器锁

  • 为什么多线程不会真的并发?答,其实只有一个线程在执行,一个线程执行时,另一个在休息。
  • GIL让多线程程序,保证同一时刻只有一个线程在运行。运行多线程时,线程之间先抢锁,再运行。
  • 官网推荐的解释器为CPython解释器,由C语言写成。由于历史原因,CPython里有GIL。
  • 多线程为什么比单线程快?答,因为网速和阻塞。

  • 计算密集型(没有延时和阻塞) : 用多进程
  • io密集型(输入输出密集型/读写/收发):用多线程、多协程

1.6解决GIL

  • 方法1: 换成Jpython等其他解释器运行
  • 方法2: 换成其他语言实现
  • 以C语言为例,实现:

在这里插入图片描述

  • 第一行,如果需要在屏幕上输出的话,就必须要这一行
  • C语言必须要有一个main函数
    编译刚才的文件:gcc 文件名
    得到一个`a.out’,运行它
    在这里插入图片描述

  1. 准备一个loop.c文件(编写死循环代码)
    在这里插入图片描述
  2. 把loop.c编译成一个动态库(linux平台下)
    在这里插入图片描述
  3. 准备一个test.py文件
    在这里插入图片描述

二、拷贝

1.深拷贝与浅拷贝

  • 浅拷贝: 只拷贝最上面这层
  • 深拷贝: 拷贝整个数据
  • Python中一般是新建指向。其它语言(C语言),一般是拷贝数据。
  • id()可以知道数据所在的地址
  • Python中拷贝:
import copy

a = 1
# 浅拷贝
b = copy.copy(a)

# 深拷贝
c = copy.deepcopy(a)
  • 当一个变量 = XXX时,约定为:这个变量指向XXX
  • 原理图:
    在这里插入图片描述
  • 说明(浅拷贝): 浅拷贝只拷贝最上层。你让我拷谁,我拷谁。把要拷贝的原封不动拷贝下来,管你里面是数据还是引用,复制就完了。
  • 说明(深拷贝): 深拷贝拷贝到了最下层。我会把最深层的数据挖出来复制一遍。
  • 浅拷贝:若最上层是不可变类型 (元组),只会建立指向。
  • 深拷贝:若所有层都是不可变类型 (元组),同样只会建立指向。只要有一层是可变类型 ,就会真正地深拷贝。

2.拷贝的其它方式

2.1切片是浅拷贝

  • b = copy.copy(a) 等同于 b = a[:]

2.2复制字典是浅拷贝

  • 字典里存的是引用(值在别的地方存着)

2.3传递参数传递的是引用

  • 传递参数传递的是引用
  • 如果不希望对原参数进行修改,那么:
    function(copy.deepcopy(参数))

三、私有化

变量名说明
XX公有变量
_XX私有化属性或方法。禁止导入。类对象和子类可以访问。
__XX避免与子类属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
__XX__魔法对象和属性
XX_用于避免与Python关键字冲突

四、import

1.1导入模块的几种方式

  • import 有两个功能。一、让python解释器去加载模块。二、定义一个变量,使它指向这个模块
导入模块
import a
import a, b
import a as A
from a import aaa
from a import aaa, bbb
from a import *

1.2导入模块的先后顺序

  • 按下面列表的先后顺序
    在这里插入图片描述
  • 添加模块的搜索路径

sys.path.append(“一个模块的路径”)

  • 搜索模块插队

sys.path.insert(0, “一个模块的路径”)

1.3重新加载模块

  • 若先导入模块且程序未结束时,修改了这个模块的代码。程序不会改变,因为原先的模块已经被加载到缓存中。再次使用import程序导入,也不会改变(import可以防止模块重复导入)。
  • 重新加载模块:
from imp import reload

reload(希望重新加载的模块名)
  • 注意: 只有import形式可以,不能用from…import形式
  • 注意: 重新加载之前,一定要先导入这个模块

1.4from的问题

  • 假如data.py文件中有一个变量a = 1,有两种方式导入
  • 方式1: import data
  • 方式2: from data import a
# 方式1,会改变data里的变量值
import data
data.a = 2  # 此时,data模块里的a值会变为2

from data import a
a = 2  # 此时,data里的a值不会变
  • 原来,from … import … ,相当于拿了一个变量名建立了对1的引用(而不是对data.py里a的引用)。a=2就是把a对1的引用,变为对2的引用。所以不会改变原模块的值。
  • 而import data,相当于拿一个变量名建立了对模块本身的引用,data.a就通过前面的data. 来找到这个模块下的a, 对其进行修改。

五、封装、继承、多态

1.封装

  • python3中每一个对象都有一个属性__class__,通过这个属性,就知道谁创建了这个对象(即它的模板),从而找到了类方法
  • __dict__可以标记一个对象中,究竟有些什么属性。
    在这里插入图片描述
  • 为什么没有num,却有num2?答,因为num2是这个实例独有的属性。
  • 方法里的self能不能改成其它的?答,能,它只是个形参,但最好遵循规定。

2.继承

  • 继承可以解决冗余
  • 继承可以进行迭代

3.多态

  • 如果没有重写父类方法,则会调用父类方法。如果重写,则调用子类方法。这种调用,但不清楚是调用子类还是父类的方法,就叫多态。

六、继承中MRO

1.重写和重载

  • python中子类写与父类同名的方法,叫做重写(就是覆盖)
  • python中的函数名就是一个变量名,这个变量名指向了一个函数而已。(所以python中几乎都是重写)
  • 重载: 同样的方法,因为传入参数的不同,导致的结果不同。(比如python中的数字相加和字符串相加)

2.多继承mro

在这里插入图片描述

2.1 父类.方法名

  • 子类可以通过父类.方法名(self, 参数)来调用父类的方法。但是有一个问题,当孙调用子1和子2的方法时,子1和子2会调用父的方法两次!
  • 代码:
    在这里插入图片描述
  • 结果:
    在这里插入图片描述

2.2 super().方法名

  • 子类可以通过super().方法名(参数)来调用父类的方法。
  • __mro__可以打印出一个对象,这个对象决定调用方法的先后顺序。
  • 代码:
    在这里插入图片描述
  • 结果:
    在这里插入图片描述
  • 以孙为例,在元组中找到孙,它的下一个是子1,所以super()调用的是子1。
  • 注意: super()里可以传参数(类名),不传时,默认使用所属类名。比如,在孙类下的super(),相当于super(孙)。

2.3 mro是什么

  • mro是python3中利用C3算法得到的元组,是一个顺序表。C3算法可以使得不会重复调用,但也导致了有时不会调用到父类方法,比如子1调用的是子2的方法,如果子2不调用父类方法,那么父类方法就不被调用。

3.单继承mro

七、*元组参数&**关键字参数

1.复习元组参数和关键字参数

  • 代码:
    在这里插入图片描述
  • 结果:在这里插入图片描述

2.关键字被作为元组参数传入了

  • 代码:
    在这里插入图片描述
  • 结果:
    在这里插入图片描述

3.拆包

  • 代码:
    在这里插入图片描述
  • 结果:
    在这里插入图片描述
  • 原来,*和**相当于拆包,一个拆元组,一个拆字典

八、类与实例、属性与方法

1. 类与实例的内存空间

  • 对象: 拥有自己的内存空间,和自己的属性方法的就叫对象。
  1. __new__=====>创建对象(有个内存空间)
  2. __init__=====>对刚刚申请的空间,进行初始化

self指向创建的实例对象。

  • 类属性只有一个(共用的都放在类对象里)。实例对象有一个方法__class__,指向类对象。通过它来访问类对象里的方法和属性。

2.通过实例对象修改类属性

  • 了解原理,别这样干
  • 实例名.类属性 = “XXX” 并不会改变类属性,只会在实例里生成一个同名的实例属性(会被优先调用)
  • 实例名.__class__.类属性 可以改变类属性。

3.实例方法与类方法与静态方法

  • 实例方法:

def 实例方法名(self):

  • 类方法:

@classmethod
def 类方法名(cls):

  • 静态方法:

@staticmethod
def 静态方法名():

  • 两者的区别是,实例方法默认传入实例对象,类方法默认传入类对象,类默认不传参数。
  • 静态方法类似于一个普通函数(把装饰器抹去,取消def前缩进与类平齐)。但是这个普通函数并不想全局使用,只想这一个类、实例使用。

4.property属性

1. property属性含义

  • property属性:

@property
def property属性名(self):

  • 调用:(因为是属性,所以不需要括号。该方法一般用以返回一个值。)

类名.property属性名

在这里插入图片描述

  • 这个可读性更高。(希望要一个结果,如果调用方法会影响可读性)
  • 面向对象,封装继承多态。这就是封装的体现。

2. property属性应用

  • 一般一个私有属性__私有属性名,会搭配一个getter公有方法,和一个setter公有方法。一个管获取,一个管设置。
  • 原代码:
    在这里插入图片描述
  • 改造后代码:
    在这里插入图片描述
  • 使用装饰器后代码:
    在这里插入图片描述

九、魔法属性

1. 私有属性

  • 为什么外部获取不了私有属性?答,名字重整。
  • __私有属性名被改为了_类名__私有属性名
  • 如果在外部使用实例名.__私有属性名 = 一个值,并不会改变私有属性的值,只会给实例添加一个实例属性。
  • 实例名.__dict__可以看到一个实例的属性,包括所属类的私有属性
  • 类名.__dict__可以看到一个类的所有属性,包括魔法属性

2.魔法属性、方法

  • 魔法方法、魔法属性: 当执行魔法方法时,对应Python解释器里的特殊操作

2.1 常用魔法属性

  • __doc__:展示类的描述信息
  • __class__:创建这个实例对象的类
  • __module__:创建这个实例对象的类,在哪一个模块里
  • __init__:初始化方法
  • __new__:创建方法。与初始化方法合称构造方法。
  • __del__:对象内存被释放时,自动触发
  • __call__:实例()触发
  • __dict__:检查类或实例对象里的所有属性
  • __str__:直接输出该对象时,该对象的返回值
    在这里插入图片描述
    在这里插入图片描述

2.2 索引魔法属性

  • 用于索引操作,当字典用。
  • __getitem__:获取数据
  • __setitem__:设置数据
  • __delitem__:删除数据
    在这里插入图片描述
    在这里插入图片描述

2.3 分片魔法属性

  • 首先,来重新认识一下切片操作
    在这里插入图片描述
  • 用于分片操作,如:列表
    在这里插入图片描述

十、with与上下文管理器

1. with

  • 文件描述符fd在一个进程里最多1024个。
def fun():
    f = open("文件名", "w")
    f.write("hello python")
    f.close()
  • 如果进程出现问题,导致close无法被正常调用,资源就会一直占用
def fun():
    f = open("文件名", "w")
    try:
        f.write("hello python")
    except IOError:
        pass
    finally:
        f.close()
  • 上面的代码,等同于:
def fun():
    with open("文件名", "w") as f:
        f.write("hello python")

2. 上下文管理器contextmanager

  • 点击APP,进入新界面时,会把之前页面的信息存储,以便可以返回。以这个新界面为基础,再点击新界面就叫下文,返回就叫上文。
  • 看书,一句话的前面就叫上文,后面就叫下文。
  • 任何实现了__enter__()和__exit__()方法的对象都可称为上下文管理器。上下文管理器可以使用with关键字。(文件对象实现了上下文管理器)
  • with语句后面要跟上下文管理器对象。
    在这里插入图片描述
  1. File(“test.txt”, “w”)会创建一个实例对象
  2. with会检查整改实例对象是否是一个上下文管理器(检查有没有__enter__()和__exit__()
  3. 如果是,with会自动地调用__enter__()方法,然后把它的返回值给as后的f
  4. 假如产生了异常,就会调用__exit__()方法

3. 利用装饰器实现上下文管理器

  • 利用yield分割。yield前的就是__enter__(),后的就是__exit__()
    在这里插入图片描述
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值