一、一切皆对象
在python中小到int、str都是一个对象,
a = 1
b = ''
c = []
d = {}
e = lambda a:a+1
print( type(a),type(b),type(c),type(d),type(e) )
print(sys.getsizeof(a),sys.getsizeof(b),sys.getsizeof(c),sys.getsizeof(d),sys.getsizeof(e))
<class 'int'> <class 'str'> <class 'list'> <class 'dict'> <class 'function'>
14 25 36 136 72
二、可变对象和不可变对象
当对象的值发生变化,但内存地址没有改变时,则说明是可变类型
当对象的值发生变化,内存地址也发生改变时,则说明是不可变类型
list、dict、set都是可变对象;int、string、tuple都是不可变对象
a = {'A':1,'B':2}
b = a
print(id(a),id(b))
a['c'] = 3
print(id(a),id(b),a,b)
a = {'A':1,'B':2,'D':3}
print(id(a),id(b),a,b)
11826688 11826688
11826688 11826688 {'A': 1, 'B': 2, 'c': 3} {'A': 1, 'B': 2, 'c': 3}
23334368 11826688 {'A': 1, 'B': 2, 'D': 3} {'A': 1, 'B': 2, 'c': 3}
三、隐藏的方法和属性
def __init__(self):通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后
def __new__(self):通常用于控制生成一个新实例的过程。它是类级别的方法
def __str__(self):如果要把一个类的实例变成 str,就需要实现特殊方法
def __repr__(self):它是一个 ”自我描述“ 的方法,此方法通常实现这样的功能: 当直接打印类的实例化对象时,系统将会输出对象的自我描述信息,用来告诉外界对象具有的状态信息。
def __dict__(self):包存了类或对象内部所有属性和方法对应的字典
def __getattr__(self,name):类不存在该属性时__getattr__函数会被激活
def __getattribute__(self,name):是属性访问拦截器,就是当这个类的属性被实例访问时,会自动调用类的__getattribute__
方法
def __setattr__(self,name,value):在类实例的每个属性进行赋值时,都会首先调用__setattr__()方法,并在__setattr__()方法中将属性名和属性值添加到类实例的__dict__属性中
def __delattr__(self,name):不建议大家直接调用__delattr__方法来删除实例的属性,不过在特定情况下可以通过重写该方法进行一些属性删除的特殊处理,确保相关实例属性释放时程序进行了正确处理
def __call__(self,arg,**key):自定义函数的调用,通常情况下是在函数名后加()
来调用。但同样也可以用__call__()方法来调用
四、迭代器、生成器、装饰器
迭代器是实现迭代器协议的对象,它包含方法 __iter__()
和 __next__()
列表、元组、字典和集合都是可迭代的对象。它们是可迭代的容器,您可以从中获取迭代器(Iterator)。
所有这些对象都有用于获取迭代器的 iter()
方法
生成器(generator)也是一种迭代器,在每次迭代时返回一个值,直到抛出 StopIteration 异常。
含有 yield 关键字的函数,调用该函数时会返回一个生成器
我们可以使用 close() 方法来关闭一个生成器。生成器被关闭后,再次调用 next() 方法,不管能否遇到 yield 关键字,都会抛出 StopIteration 异常
装饰器的作用就是为已经存在的对象添加额外的功能
内置的装饰器有三个,分别是staticmethod、classmethod和property,作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。
五、异步编程:多线程、多进程、协程
concurrent.futures
模块 ThreadPoolExecutor
和ProcessPoolExecutor
通过submit函数提交执行的函数到线程池中,submit函数立即返回,不阻塞
done方法用于判定某个任务是否完成
cancel方法用于取消某个任务,该任务没有放入线程池中才能取消成功
result方法可以获取task的执行结果
as_completed方法一次取出所有任务的结果,as_completed()方法是一个生成器,在没有任务完成的时候,会阻塞,在有某个任务完成的时候,会yield这个任务,就能执行for循环下面的语句,然后继续阻塞住,循环到所有的任务结束。从结果也可以看出,先完成的任务会先通知主线程。
map方法,无需提前使用submit方法,map方法与python标准库中的map含义相同,都是将序列中的每个元素都执行同一个函数。
wait方法可以让主线程阻塞,直到满足设定的要求
- future的设计理念很棒,在线程池/进程池和携程中都存在future对象,是异步编程的核心。
- ThreadPoolExecutor 让线程的使用更加方便,减小了线程创建/销毁的资源损耗,无需考虑线程间的复杂同步,方便主线程与子线程的交互。
- 线程池的抽象程度很高,多线程和多进程的编码接口一致。
协程是也是实现多任务的一种方式
协程yield的代码实现
gevent内部封装的greenlet,其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO
六、并发编程:asyncio、threading
threading.Thread () 创建
在python中,主线程是第一个启动的线程。
~父线程:如果启动线程A中启动了一个线程B,A就是B的父线程。
~子线程:B就是A的子线程。
一个线程中调用另一个线程的join方法,调用者被阻塞,直到调用线程被终止
~run():用以表示线程活动的方法
~start():启动线程
~join():等待至线程终止
~isAlive():返回线程是否活动的
~getName():返回线程名称
~setName() : 设置线程名称
python的threading模块提供了RLock锁解决方法。在某一时间只能让一个线程操作的语句放到RLock的acquire方法和release方法之间,即acquire相当于给RLack上锁,而release相当于解锁
七,cpython、GIL
Python(CPython)将Python源码编译成CPython字节码,再由虚拟机解释执行这些字节码。
python将py文件编译成为PyCodeObject,再将这个对象写入某文件就成为了pyc文件,文件中包含python的magic number(来说明编译时使用的python版本号)、源文件的mtime(使pyc和py文件保持同步)、编译出的code对象
Python Virtual Machine,简写为PVM,当有字节码文件之后,就会被发送到PVM里来执行。
这里注意,PVM并不是指的一个独立的程序,是不需要安装的。可以把PVM理解为Python的运行引擎,是一个迭代运行字节码指令的大循环,一个个的完成操作,直到结束。
从技术角度看,PVM才是“解释器”的最后一步。
Python有多个解释器实现。分别用C,Java,C#和Python编写的CPython,Jython,IronPython和PyPy是最受欢迎的。GIL仅存在于CPython的原始Python实现中
GIL:⼜叫全局解释器锁,每个线程在执⾏的过程中都需要先获取GIL,保证同⼀时刻只有⼀个线程在运⾏,⽬的是解决多线程
同时竞争程序中的全局变量⽽出现的线程安全问题。