GIL(全局解释器锁)
- Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL。
- GIL:全局解释锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
- 线程释放GIL锁的情况:在IO操作等可能会引起阻塞的system call之前。可以暂时释放GIL,但在执行完毕后,必须重新获取GIL Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100
- Python哦使用多进程是可以利用多核的CPU资源的。
- 多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁
计算密集型:多进程
IO密集型:多线程、协程
想要解决GIL问题:可以换解释器,或者用其他语言来解析
深拷贝、浅拷贝
a = [11,22]
b = a
复制的并不是[11,22]这个列表,而是复制a指向该列表的引用,这仅仅是指向
通过import copy,调用deepcopy函数,如c = copy.deepcopy(a),拷贝的是列表,而不是引用,这是深拷贝
使用copy.copy()复制的是一个新的内容,但里面具体的内容是复制的引用,这就是浅拷贝,复制的内容一成不变,这是浅拷贝;使用copy.deepcopy()是在一个新的空间里复制一遍,而不是引用,这是深拷贝。
如果copy.copy拷贝的是元组,那么它不会进行浅拷贝,仅仅是指向。原因:因为元组是不可变类型,那么意味着数据一定不能修改,因此用copy.copy的时候它会自动判断,如果是元组它就是指向了它
如果用copy.copy、copy.deepcopy对一个全部都是不可变类型的数据进行拷贝,那么它们结果相同,都是引用指向。如果拷贝的是一个拥有可变类型的数据,即使元组为最顶层,那么deepcopy依然是深拷贝而copy.copy还是指向
私有化
- xx:公有变量
- _x:单前置下划线,私有化属性或方法,from somemodule import * 禁止导入,类对象和子类可以访问
- __xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
- __xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__, __不要自己发明这样的名字
- xx_:单后置下划线,用于避免与Python关键词的冲突
通过name mangling(名字重整(目的就是以防子类意外重写基类的方法或者属性)如:_Class__object)机制就可以访问private了。
import导入模块
from xxx import yyy、
import xxx
from xxx import *
import xxx,zzz
from xxx import yyy,mmm
import xxx as XXX(重命名 )
from imp import reload
reold(xxx)重新加载模块
多继承以及MRO顺序
多继承时使用super时调用父类方法是按照mro顺序,Grandon.__mro__是一个存有mro数据的元组,而super()也可以指定调用的父类方法
参数 * 和 ** 传参时如果有多余的参数,* 表示多余的一般参数会保存在一个元组里,** 表示带键值对的多余参数将会保存在一个字典里
类对象、实例对象、类方法、实例方法、类属性、实例属性、静态方法
类对象相当于模板,而实例对象相当于类对象实例化
方法包括:实例方法、静态方法、类方法,三种方法在内存中都归属于类,区别在于调用方式不同
- 实例方法:由对象调用;至少一个self参数;执行实例方法时,自动将调用该方法的对象赋值给self;
- 静态方法:由类调用;无默认参数;
property属性
property是一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法,它在调用时并不是调用函数,而是直接调用返回值
创建property属性的方式
property属性有两种方式
- 装饰器 即:在方法上应用装饰器
- 类属性 即:在类中定义值为property对象的类属性
装饰器方式
在类的实例方法上应用@property装饰器
Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。(如果)类继object,那么该类是新式类
新式类三种使用property装饰器
@property
def price(self, value):
print("@property")
@price.setter
def price(self, value):
print("@price.setter")
@price.deleter
def price(self)
print("@price,deleter")
通过类属性创建property属性
class Foo:
def get_bar(self):
return "laowang"
BAR = property(get_bar)
obj = Foo()
result = obj.BAR # 自动调用get_bar方法,并获取方法的返回值
print(result)
名字重整
私有属性的原因,Python中为了找不到私有的属性,把名字改了,造成了这种假象,可以通过调用__dict__来查看重整后的名字,
规律是在私有名字前加上类名加上单下划线
魔法属性
无论人或事物往往都有不按套路出牌的情况,Python的类属性也是如此,存在着一些具有特殊含义的属性,详情如下:
1.__doc__
- 表示类的描述信息
clas FOO:
""" 描述类信息,这是用于看片的神器 """
def func(self):
pass
print(Foo.__doc_\_\)
#输出:类的描述信息
2.__module__和__class__
- __module__ 表示当前操作的对象在那个模块
- __class__ 表示当前操作的对象的类是什么
test.py
# -*- coding:utf-8 -*-
class Person(object):
def __init__(self):
self.name = "laowang"
main.py
from test import Person
obj = Person()
print(obj.__module__) # 输出 test 即: 输出模块
print(obj.__class__) # 输出 test.Person 即:输出类
3.__init__
- 初始化方法,通过类创建对象时,自行触发执行
class Persom:
def __init__(self,name):
self.name = name
self.age = 18
obj = Person("laowang") # 自动执行类中的__init__方法
6.__del__
- 当对象在北村中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,__del__的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
pass
5.__call__
- 对象后面加括号,触发执行。
注:__init__方法的执行是由创建对象触发的,即:对象 = 类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象()或者类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args ,**kwargs):
print("__call__")
with与上下文管理器
普通版:
def m1():
f = oper("output.text", "w")
f.write("python之禅")
f.close()
这样写有一个潜在的问题,如果在调用write的过程中,出现了异常进而导致后续代码无法继续执行,
close方法无法被正常调用,因此资源就会一直被该程序占用者释放。
进阶版:
def m2():
f = oper("output.text", "w")
try:
f.write("python之禅")
except IOError:
print("oops error")
finally:
f.close
上下文管理器
任何实现了__enter__()和__exit__()方法的对象都可以称之为上下文管理器,上下文管理器对象可以使用with关键字,显然,文件(file)对象也实现了上下文管理器。
那么文件对象是如何实现这两个方法的呢?我们可以模拟实现一个自己的文件夹,让该类实现__enter__()和__exit__()方法。
class File():
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print("entering")
self.f = open(self.filename, self.mode)
return self.f
def __exit__(self, *args):
print("will exit")
self.f.close()
enter()方法返回资源对象,这里就是你将要打开的那个文件对象,exit()方法处理一些清理工作。因为File类实现了上下文管理器,现在就可以使用with语句了
with File("out.txt", "w") as f:
print("writing")
f.write("hello, python")
这样,你就无需显示地调用close方法了,由系统自动去调用,哪怕中间遇到异常close方法也会被调用。