- python是静态还是动态类型?是强类型还是弱类型?
动态类型语言
动态还是静态指的是编译期还是运行期确定类型 无类型声明
强类型:js数字转字符串会自动转换是弱类型 不会自动转换 - python作为后端语言的优缺点?
1.胶水语言,轮子多,应用广泛
2.语言写起来快
3.性能比较慢,python2 python3 不兼容 - 什么是鸭子类型?
关注对象的行为【方法】,而不是类型
比如file StringIO socket 对象都支持read/write方法(file like object)
再比如定义了_iter_魔术方法的对象可以用for迭代 - 什么是monkey patch?那些地方用到了?自己如何实现?
所谓的monkey patch就是运行时类型替换
比如gevent库需要修改内置的socket
from gevent import monkey;
monkey.patch_socket()
(把内置阻塞的库替换成非阻塞的socket) - 什么是自省?
运行是判断一个对象的类型的能力。
python一切皆对象 - is 和 == 区别?
is:比较的是两个对象的id值是否相等,也就是比较两个对象是否是同一个实例,是否指向同一个地址。
==:比较的是两个对象的内容是否相等,默认会调用对象的__equal__()方法
python所做的性能优化:
1.小整数对象[-5,256]是全局解释器范围内被重复使用,永远不会被GC回收。
2.同一个代码块中的不可变对象,只要是值相等的,就不会重复创建新的对象。
3.字符串中单个20以内他们的内存地址一样,单个21以上,内存地址不一样
- 什么是列表和字典推导?
一种快速生成list/dict/set的方式 - 什么是生成器,迭代器?
1.生成器定义
在Python中,一边循环一边计算的机制,称为生 成器:generator。
生成器仅仅保存了一套生成数值的算法,并且没有让这个算法现在就开始执行,而是我什么时候调它,它什么时候开始计算一个新的值,并给你返回。
1)生成器(generator)能够迭代的关键是它有一个next()方法,
工作原理就是通过重复调用next()方法,直到捕获一个异常。
(2)带有 yield 的函数不再是一个普通函数,而是一个生成器generator。
可用next()调用生成器对象来取值。next 两种方式 t.__next__() | next(t)。
可用for 循环获取返回值(每执行一次,取生成器里面一个值)
(基本上不会用next()来获取下一个返回值,而是直接使用for循环来迭代)。
(3)yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
(4).send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果
——换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,a = yield 5,第一次迭代到这里会返回5,a还没有赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10
我又想要得到庞大的数据,又想让它占用空间少,那就用生成器。
迭代原理
面试题:for循环的原理是什么?
答:1. 获取迭代器
2. 循环获取下一个元素
3. 遇到异常停止迭代
可以被for的条件是什么?
答:能被for的对象必须具备__iter__方法
答:能被for的对象是可迭代对象
2.迭代器是一个可以记住遍历的位置的对象。
迭代器有两个基本的方法:iter() 和 next()。
- python2/3差异常考题
1.python3中print为函数,python2中print为关键字。
2.编码问题 python3不再有Unicode对象,默认str就是unicode
3.除法返回浮点数
4.string 字母 大小写字符串
string.letters:包含所有字母(大写或小写)的字符串
Python 3.0中,string.ascii_letters.
5.python 2.7 cmp(x,y)函数用于比较2个对象,如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1
python3.7 cmp()已经不存在了,如果你需要实现比较功能,需要引入 operator 模块,适合任何对象
6.python3可以加类型注解,帮助IDE实现类型检查
7.优化的super()方便直接调用父类函数
8.高级解包操作:
9.参数传递: - Python新增
yield from 链接子生成器
asyncio内置库
新增库enum - python3改进
生成的pyc文件统一放到_pychche_
一些内置库的修改 urllib selector
dict性能优化 - python如何传递参数?
对象引用的方式传递
默认参数只计算一次
不可变对象:bool,int,float,tuple,str
可变对象:list set dict - 函数传递中*args,**kwargs含义是什么?
*args 被打包成tuple
**kwargs 字典 - 什么时候需要捕获处理异常呢?看python内置异常的类型。
1.网络请求(超时,连接错误)
2.资源访问(权限问题)
3.代码逻辑异常
finally:无论异常有没有发送都会执行的代码,一般处理资源的关闭和释放 - 什么是Cpython GIL
GIL:global interpreter lock
Cpython使用简单的锁机制避免多个线程同时执行字节码。
限制了程序的多核执行
同一个时间只能有一个线程执行字节码
CPU密集程序难以利用多核
IO期间会释放GIL,对I/O密集程序影响不大
CPU:cpu密集可以使用多进程+进程池
IO:IO密集使用多协程、线程 - 如何剖析程序性能
使用内置的profile/cprofile等工具 - 服务端性能优化措施
1.数据结构与算法优化
2.数据库层:添加索引,批量操作,减少IO
3.缓存:使用内存数据库redis
4.异步框架:asyncio
5.并发:gevent/多线程 - 什么是生成器?
可以生成值的函数
当一个函数里有了yield关键字就成了生成器
生成器可以挂起执行并且报存当前执行的状态
19.什么是单元测试?
单元测试相关库:nose/pytest
如何设计测试用例:
1.正常值功能测试
2.边界值(比如最大,最小,最左最右)
3.异常值 (比如None,空值,非法值)
- Python深拷贝和浅拷贝?
深拷贝:又开辟了一块空间,复制过来
浅拷贝:指向的是同一个对象 - 如何捕获异常,常用的异常机制有哪些?
如果我们没有对异常进行任何预防,那么在程序执行的过程中发生异常,就会中断程序,调用python默认的异常处理器,并在终端输出异常信息。
try…except…finally语句:当try语句执行时发生异常,回到try语句层,寻找后面是否有except语句。找到except语句后,会调用这个自定义的异常处理器。except将异常处理完毕后,程序继续往下执行。finally语句表示,无论异常发生与否,finally中的语句都要执行。
assert语句:判断assert后面紧跟的语句是True还是False,如果是True则继续执行print,如果是False则中断程序,调用默认的异常处理器,同时输出assert语句逗号后面的提示信息。
with语句:如果with语句或语句块中发生异常,会调用默认的异常处理器处理,但文件还是会正常关闭。
- 函数装饰器有什么作用(常考)
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
闭包的实现
Python中的装饰器是通过闭包实现的,简单地讲,闭包就是引用了外部变量的内部函数,而闭包的实现正是利用了以上函数特性,下面我们来看看闭包是如何实现的:
def outer(x):
def inner(): # 函数嵌套
return x # 跨域访问,引用了外部变量x
return inner # 函数作为返回值
2.简述Python的作用域以及Python搜索变量的顺序
Python作用域简单说就是一个变量的命名空间。代码中变量被赋值的位置,就决定了哪些范围的对象可以访问这个变量,这个范围就是变量的作用域。在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域。Python的变量名解析机制也称为 LEGB 法则:本地作用域(Local)→当前作用域被嵌入的本地作用域(Enclosing locals)→全局/模块作用域(Global)→内置作用域(Built-in)
- 新式类和旧式类的区别,如何确保使用的类是新式类
为了统一类(class)和类型(type),python在2.2版本引进来新式类。在2.1版本中,类和类型是不同的。
为了确保使用的是新式类,有以下方法:
放在类模块代码的最前面 metaclass = type
从内建类object直接或者间接地继承
在python3版本中,默认所有的类都是新式类。
- 简述__new__和__init__的区别
创建一个新实例时调用__new__,初始化一个实例时用__init__,这是它们最本质的区别。
new方法会返回所构造的对象,init则不会.
new函数必须以cls作为第一个参数,而init则以self作为其第一个参数.
基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。
以下情况是导致引用计数加一的情况:
对象被创建,例如a=2
对象被引用,b=a
对象被作为参数,传入到一个函数中
对象作为一个元素,存储在容器中
下面的情况则会导致引用计数减一:
对象别名被显示销毁 del
对象别名被赋予新的对象
一个对象离开他的作用域
对象所在的容器被销毁或者是从容器中删除对象
分代回收
分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象
- Python中的@property有什么作用?如何实现成员变量的只读属性?
@property装饰器就是负责把一个方法变成属性调用,通常用在属性的get方法和set方法,通过设置@property可以实现实例成员变量的直接访问,又保留了参数的检查。另外通过设置get方法而不定义set方法可以实现成员变量的只读属性。
- *args and **kwargs
*args代表位置参数,它会接收任意多个参数并把这些参数作为元组传递给函数。**kwargs代表的关键字参数,允许你使用没有事先定义的参数名,另外,位置参数一定要放在关键字参数的前面。
- 有用过with statement吗?它的好处是什么?具体如何实现?
with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
- List item