-
Notifications
You must be signed in to change notification settings - Fork 0
/
python.txt
125 lines (101 loc) · 11.1 KB
/
python.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
python你问我答
聊聊python的迭代器?
说到迭代器,就要说到可迭代对象,凡是实现了xx方法的都是可迭代对象
说说生成器,以及它与迭代器的关系
协程是什么,它跟迭代器和生成器有关系吗
python的内存管理机制
python的垃圾回收机制
python的垃圾回收有两种方式,首先第一种就是引用计数,当一个变量指向一个对象时,那么这个对象的引用计数+1,当该变量指向其他时,则该对象的引用计数-1,当对象的引用计数为0的时候,就会在下一次的垃圾回收中会回收掉
但是对于循环引用的对象,引用计数是没法清理的。这时就需要用到第二种方式,那就是分代回收,python的分代回收分为三代:
说一说python的GIL锁?
GIL是python为了处理线程并发引入的一种全局变量锁,也即是一个进程中,同一时刻只有一个线程在执行
用过python的装饰器吗?用在什么地方?
装饰器主要是用来扩展已经封装的代码的功能,达到无侵入性的修改原代码的能力,有点类似java的aop切面编程
比如给接口统一增加权限校验,参数校验等等
那它的底层实现,你了解过吗?
装饰器主要是利用闭包实现的,闭包就是引用了外部变量的内部函数
在python中,一切都是对象,函数也不例外。既然是对象,那么就有如下性质:
* 作为函数参数
* 赋值给变量
* 作为函数返回值
而python的闭包就是应用了这些特性,cpython在代码对象数据结构中定义了两个变量co_freevars和co_cellvars
说说python的wsgi
wsgi是python的web规范,类似于java的servlet规范,一个web系统一般都涉及到请求的处理,回复的处理,网络连接等操作,每个系统都需要自己实现一遍,另外,由于每个系统的实现不一样,导致无法随意的移植到任何其他web服务器上。
为了解决这种异构性,以及实现业务与web服务的解耦,每个语言都会推出一套规范,只要web服务器和应用都遵循该规范,那么就可以任意的移植,并且团队也只需要关注自身业务逻辑,而不需要关注web网络的相关处理。
对于python的wsgi而言,由如下几部分组成:
1、web server
2、application
3、middleware(可选)
其中,web server通过将socket封装成environ对象(包含请求的相关信息,header、body等等),并且提供一个start_response回调方法
application是一个可调用对象(也就是实现了__call__方法),web server调用application对象,传递environ和start_response参数进来,application处理完了之后,将结果通过start_response回调给web server,由web server返回给请求调用方
middleware就是一个个中间件,处于web server和application之间,一般用来做一些业务之外的公共事项,比如鉴权、日志搜集等等
说说python中的协程
协程有的也称为用户态线程,是一种主动式的任务调度方式,区别于线程的抢占式调度。
python最开始的协程是通过生成器来实现的,通过yield实现函数的执行、暂停和继续,因为协程是多任务间的协作,这就涉及到各个任务间的数据传递,python通过定义了send方法来传递参数给一个协程,随后有定义了yield from关键字来支持获取协程的结果。
在python3.4时,为了让协程的编写方式跟生成器分开,体现协程概念,推出了asyncio库,随后在3.6正式推出wait和notify等协程原语。
那你说说yield在底层是怎么实现的,与了解吗
Python在解释代码时,是将代码块加载为一个叫PyFrameObject的对象,这个对象代表了当前运行的栈帧。PyFrameObject里有个f_lasti变量用于保存代码当前执行到了字节码的哪个位置。在第二次执行a.next()时,生成器对象把之前携带了f_lasti的PyFrameObject当参数传给PyEval_EvalFrameEx,在PyEval_EvalFrameEx里的执行一个JUMPTO就直接跳转到了上一次结束生成器时的字节码位置。所以生成器对象每次执行结束都把字节码的偏移量记录下来,并把运行状态保存在PyFrameObject里,下一次运行时生成器时,python解释器直接按照偏移量寻找下一个字节码指令。
说说python中的asyncio的实现机制
python具有多继承吗?
严格来说,python是没有多继承的,它的多继承是通过单继承和mixin组合来实现的
你说到了mixin,什么是mixin呢?
mixin就是混入的意思,它实际上也是一个类,其他类也可以继承它,但是它的定位不是作为一个对象类型,而是作为一个功能封装类,让其他类通过继承组合它的功能。
对于多继承来说(暂且叫它多继承吧),那你说说它的mro机制呢?
mro就是方法解析顺序,是指当多继承的时候,子类的方法的搜索顺序。那就从mro的发展来说,在python2.1之前(经典类),mro是通过从左到右深度优先搜索来实现的,会去掉后面重复出现的类。这种机制的问题就是会出现,先搜索到基类的方法,从而错过实际子类复写的方法,与预期不符合。在python2.2以后(新式类),mro改进了该机制,在原有的从左到右深度优先搜索的情况下,对于重复的出现的类,保留最后出现的。但是这样也会出现子类改变了父类的方法搜索顺序,违反了单调性原则。在python2.3以后,采用了c3机制来实现mro,这个方法比较复杂,参考文档:https://hanjianwei.com/2013/07/25/python-mro/
怎样实现python的单例?
可以从四种方式来实现
1、方法装饰器:利用了闭包的原理,在闭包函数中进行控制
2、类装饰器:主要利用了可调用对象的原理,也就是该装饰器类重写了__call__方法,在方法中进行控制
3、自定义类的__new__方法:因为对象是通过类的__new__方法实例化出来的,要控制对象的实例化,就可以从这个方法入手。
4、使用元类:类是通过元类的__new__方法实例化出来的,而对象是通过类对象(类也是元类的对象)调用(可调用对象)产生的,要让对象可以调用,那么就需要其类实现__call__方法即可,也就是只要在元类__call__方法中控制即可。
说一说python的函数参数?
在python中,函数的参数类型分为如下几种:
1、位置参数:调用传参跟函数参数必须一一对应
2、默认参数:以key=value形式定义,调用方可以不用传递,函数中使用方法定义时默认的值
3、不定参数:以*args形式定义,调用方可以传0个或任意多个参数
4、关键字参数:以**kwargs形式定义,调用方可以传0个或者任意多个key=value形式的参数
5、命名关键字参数:可以单独以key定义,也可以以key=value形式定义,需要以 * 或者 *args 分割,
python的参数传递是值传递还是引用传递?
我认为都是值传递,只是对于复杂类型来说,传递的是变量实参执行的对象的地址值拷贝,也就是说实参和形参此时指向的地址都是一样的,所以才会有对于复杂类型,函数内的修改会影响函数调用值。
只要在函数中操作的都是同一个地址,那么就会影响传递的值,如果是新创建的一个对象,那么就不会影响传递的值。
说一说python的作用域?
那分别说说四大作用域吧,也就是LEGB:
1、Local:局部作用域,这个作用域中的对象的生命周期只存在于定义它的方法、函数、类中等等
2、Enclosed:嵌套作用域,主要存在于闭包中,也就是嵌套函数中,一个函数内部的嵌套函数可以访问到该函数的变量
3、Global:全局作用域,主要存在于模块变量中,也就是在一个模块顶层定义的变量,它对该模块中的任何地方都可见
4、Built-in:解释器内置变量的作用域
因为python的语言不需要声明,因此在不同的作用域中初始化赋值同一个对象,其实是相互不影响的,通俗来说,就是在同一个对象上多贴了一个标签而已。
另外还有一点;只有当变量在Module(模块)、Class(类)、def(函数)中定义的时候,才会有作用域的概念,在一般的代码块中,是没有作用域的,离开代码块,也是可以访问到该变量的。
说一说python中上下文管理器?
上下文管理器,也就是可以使用with关键字修饰的对象,进入with代码块之前,会首先执行该对象的__enter__方法,退出with代码块之前,会执行该对象的__exit__方法
因此只要一个类实现了这两个方法,就可以作为一个上下文管理器使用。主要使用的场景是对于资源的管理,比如连接的初始和关闭等等
说一说python中的缓存?
python的运行时缓存分为两部分来看,同一代码块和不同代码块
同一代码块中,所有的数字都会缓存;布尔值也会缓存;非乘法字符串都缓存;1倍乘法字符串(xxx * 1)都会缓存;大于1倍的,如果字符串只包含字母数字下划线并且长度小于等于20则缓存。
不同代码块中,-5 ~ 256的数字都缓存,字符串跟同一代码块有细微的区别,具体有点忘了。
https://www.cnblogs.com/jin-xin/articles/9439483.html
python中字典的实现
是通过hash实现的,首先定义出一个,通过hash函数计算出一个值,然后跟数组长度-1 取模,如果发生hash碰撞,则采用线性地址法进行探测。
知道python的内存实现机制吗?
python的内存管理是一个4层的金字塔结构
1、L0:操作系统层自己管理的内存申请和回收,python不能干涉,如c语言的(molloc和free)
2、L1:python封装了底层操作系统的方法,由python提供统一的内存管理,屏蔽底层差异性(pymem_api)
3、L2: python进一步提供了对象级别的内存管理接口(pyobj_new),GC就对应于这一层
4、L3:提供各类对象的缓存池机制
python常见的数据结构
1、列表(list):可变,元素可以是任何类型,可以是多种类型混杂
2、元组(tuple):不可变,元素可以是任何类型,可以是多种类型混杂
nametuple(命名原则):类似于类定义,可通过属性访问
3、集合(set):可变,元素只能是可hash对象,也就是可以具有__hash__方法
frozenset(不可变集合)
4、字典(dict):可变,元素只能是可hash对象,也就是可以具有__hash__方法
defaultdict(带默认值的字典):当通过[]访问的时候,会赋予默认值,但是通过get()访问不会
OrderDict(有序字典)
5、字符串(str):不可变
6、数组(array.array):可变,元素只能是基本类型,不能多种类型混杂
7、Lifoqeue:带锁语义的同步栈
8、Queue:带锁语义的同步队列
9、Counter:元素计数器,类似于字典的访问方式,key为统计的元素值,value为元素个数
10、heapq:小顶堆
11、PriorityQueue:优先级队列,内部基于heapq,带锁语义的同步队列
12、bisect:二分排序算法,在有序的列表中插入数据是很快的