1、GIL(Global Interpreter Lock)
全局解释器锁就是CPython解释器内部的锁,与Python语言是没有关系的。是解释器为了锁住解释其内部的全局资源,每个线程想要运行,首先要获取GIL,而GIL本身就是一把互斥锁,造成所有线程只能一个一个并发交替执行。
1.1、GIL被释放的三种情况:
- 当前线程执行完
- 当前线程执行阻塞操作时会自动释放,如I/O操作,所以多线程爬取比单线程爬取性能有提升,因为遇到IO阻塞会自动释放GIL锁。
- 当前线程执行超时(Python3使用计时器,当时间达到阈值时会释放)的时候被释放
结论:
适用于 I/O密集型程序<多线程效率比单线程高>
不适于 CPU密集型程序<多线程效率比单线程低>
1.2、区分CPython解释器的GIL锁和线程中的互斥锁:
GIL是解释器层面的,只有CPython解释器有,其他解释没有。而互斥锁是python语言层面的锁。CPython解释器有GIL锁,但是Python语言中线程互斥锁还是被需要的,只有GIL锁是无法对全局资源进行安全的保护。主要原因是GIL在当前线程没执行完有可能被释放。
2、赋值-浅拷贝-深拷贝
2.1、赋值
对象之间的赋值本质是对象之间的地址引用的传递。也就是多个对象指向同一个内存空间。
2.2、浅拷贝
浅拷贝是对一个对象顶层数据的拷贝。
2.3、深拷贝
深拷贝是对一个对象所有层次的拷贝(递归)
2.4、拷贝的其他方式
- 切片表达式,可以复制一个序列
- 字典的copy方法可以拷贝一个字典
这两种方式的拷贝都属于浅拷贝。
2.5、注意点
浅拷贝对不可变类型和可变类型的copy不同。
- copy.copy对可变类型进行浅拷贝。
- copy.copy和copy.deepcopy对不可变类型的拷贝没有意义。
3、import导入模块
导入指定目录下的的模块:
- 将模块所在的路径在程序中添加到sys.path列表中,该方法灵活,但是终端重启后需要重新添加路径。
- 修改操作系统的PYTHON_PATH环境变量 export PYTHON_PATH=$PYTHON_PATH:路径
import A 和 from A import B 的区别
- import A在当前作用域创建一个A对象<保存模块对象的引用>
- from A import B 在当前作用域创建一个B<保存A模块对象的B的引用>
可变类型的模块对象属性两种方式都可以修改,不可变类型的模块对象属性,import A可以修改,而form A import B不可修改。
3、多继承及MRO顺序
3.1、多继承
在子类初始化的时候需要手动调用父类的初始化方法进行父类的属性的构造,不然就不能使用提供的属性。
- 父类名.init()
- super(cls, self).init()
3.2、MRO顺序
- MRO顺序的意义:把所有类全部映射到这条线性结构上 保证所有类在该顺序上都只出现一次。
- super的意义:使用MRO顺序调用 每一个类 ; 保证每个类都只调用一次<初始化一次> 查找当前类在MRO顺序中下一个类 参数1是当前类 参数2是实例对象。
- 查看MRO顺序:print(对象.__ mro __)或者(对象.mro())前者返回元组,后者返回列表。
4、property属性
4.1、使用property的好处
如果不加property属性,对象的属性不加访问权限,用户可以用对象.属性方便的修改,但是,不限制对属性的修改会造成数据异常或错误;要是对象的属性设置权限,用户操作起来比较复杂;使用property属性后用户操作更简单、安全。
4.2、property属性的功能
Python的property属性的功能是:
property的作用就是 将一个属性的操作方法封装为一个属性,用户用起来就和操作普通属性完全一致,非常简单。
4.3、property属性的设置
方法一:
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
self.__age = age
@age.deleter
def age(self):
del slef.__age
print("已删除")
person = Person
print(person.age) # 打印当前年龄 '对象.age'
person.age = 111 # 通过 '对象.age = ' 可以直接修改
print(person.age) # 111
del person.age # "已删除"
方法二
# property属性设置:x = property(get_x, set_x, del_x, "doc")
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = age
def get_age(self):
return self.__age
def set_age(self, age):
self.__age = age
def del_age(self):
del slef.__age
print("已删除")
age = property(get_age, set_age, del_age, "describ")
person = Person(18)
print(person.age) # 打印age
person.age = 111 # 设置年龄为111
print(person.age) # 验证 111
desc = Person.age.__doc__ # 注意这里Person是类对象,前面的person都是实例对象
print(desc) # 打印describe
del person.age # 已删除
5、魔法属性
5.1、__ doc __
表示类的描述信息
class Foo(oject):
"""描述类信息,这是个与鱼人类"""
pass
print(Foo.__doc__) # 描述类信息,这是个与鱼人类
5.2、__ init __ 构造方法,初始化方法,通过类创建对象时,自动触发
5.3、__ del __ 当实例对象被释放时,自动触发(临终遗言)
5.4、__ call __ 当实例对象后面加上括号是,自动触发(装饰器类)
5.5、__ str __ 实例对象的返回值,当打印时,就可以看到
5.6、__ dict __ 类对象和实例对象中的所有属性返回字典
6、with与“上下文管理器”
6.1、使用with的好处
上下文管理器本质就是能够支持with操作
任何实现了 enter() 和 exit() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。
enter() 方法返回资源对象,,exit() 方法处理一些清除工作。
6.2、定义实现上下文管理器的类
class OpenFile(object):
def __init__(self, file_name, file_model):
self.file_name = file_name
self.file_model = file_model
def __enter__(self):
"""上文---提供资源"""
print("正在进入上文")
self.file = open(self.file_name, self.file_model)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
"""下文----关闭资源"""
print("正在进入下文")
self.file.close()
with OpenFile("log.txt", "r") as file:
file_data = file.read(10)
print(file_data)
6.3、通过contextmanager装饰器更方便的实现上下文管理器
from contextlib import contextmanager
@contextmanager
def open_file(file_name, file_model):
print("进入上文")
f = open(file_name, file_model)
yield f
print("进入下文")
f.close()
with open_file("log.txt", "r") as f:
while True:
f_data = f.read(10)
if f_data:
print(f_data)
else:
break