1、list(列表)和tuple(元组)的区别?
list是可变的对象,而tuple是不可变的对象。list可变的原因:虽然是list中的元素变了,但是list对象本身内存地址并没有变。
2、 什么是pep8, pep8能说出几点?
pep8是python enhancement proposal的缩写,即python增强建议书,而8的话是特指PEP8时是有关代码风格的规定的代指。
① 使用4个空格来缩进代码,不要用tab制表符,也不要tab和空格混用,对于行连接的情况。
② 如果可以,注释单独占一行。单行代码:# ,多行代码:单三引号"""或多三引号""" """。
③ 使用文档字符串,文档字符串使用三引号包裹。
④ 运算符周围和逗号后面使用空格,但是括号里面逗号不加空格:a = f(1,2) + g(3,4)
⑤ 折行以确保其不会超过79个字符。这有助于小显示器用户阅读,也可以让大显示器能并排显示几个代码、文件。
3、 Python内存管理
内存管理是指有效分配,重新分配和协调内存的过程。以便所有不同的进程之间都能平稳运行并可以最佳地访问不同的系统资源。内存管理还涉及清除不再访问对象的内存。
内存管理是以引用计数为主,分代回收,标记清除为辅的垃圾回收方式进行内存回收。
并且还引入小整数缓冲池和常见简单字符串驻留区的内存缓冲池机制。
引用计数:最重要的内存管理技术,管理内存回收:当对象的引用计数为0的时候,销毁对象。
python中每个对象都维护一个引用计数字段,记录该对象被引用的次数。
当新得引用指向的时候,引用计数+1。
当无效的引用发生的时候,引用计数-1。
当对象的引用计数为0的时候,销毁对象,可以被垃圾回收。
垃圾回收:三种情况触发垃圾回收。
调用gc.collect()。
GC达到调用值。GC机制:找垃圾,清除垃圾。
程序想退出时。
4、Python常用模块有哪些 能不能说一下 怎么使用 用来干过什么?
常用模块:requests模块、random模块、string模块、re模块、datetime、date、time模块、
paramiko模块、psutil模块等等
requests模块:Requests模块是python的内置模块,是一个用于网络请求的模块,主要用来模拟浏览器发HTTP请求。
random模块: 主要用于生成随机数。
string模块:string模块主要包含关于字符串的处理函数。
re模块:re模块是python独有的匹配字符串的模块,该模块中提供的很多功能是基于正则表达式实现的,而正则表达式是对字符串进行模糊匹配,提取自己需要的字符串部分。
datetime模块提供了五个常用类:date、time、datetime。用于处理日期和时间的类,对于基本的时间表示方法、时间戳。
Paramiko模块是用python语言写的一个模块,远程连接到Linux服务器,查看上面的日志状态,批量配置远程服务器,文件上传,文件下载等。
psutil模块:psutil是一个跨平台库的,能够轻松实现获取系统运行的进程和系统利用率(包括CPU、内存、磁盘、网络等)信息。它主要用来做系统监控,性能分析,进程管理。它实现了同等命令行工具提供的功能。
5. Python中的多进程和多线程 都使用什么模块?
python中常用的多线程模块是threading,常用的多进程模块是multiprocessing。
__name__=="__main__": #创建多进程,需要将创建多进程的代码写入if模块包里面 # #这个是用于测试,如果是直接运行的话需要写入,如果是导入运行的话不需要写入
线程是操作系统进行调度的最小单位。
进程是正在运行的程序,是系统进行资源分配的最小单位。进程起来的时候需要进行资源分配。
进程状态的模型:就绪态、运行态(running)、阻塞态
进程和线程之间的联系与区别:
1、进程调度相当于线程调度,进程里面包含线程,进程中可以进行多个线程。
2、一个进程中至少含有一个线程,这些线程都是共享这些进程的内存空间的。
3、不同进程之间内存空间都是独立的。
4、创建新的线程很简单,创建一个新的进程都需要对其父进程进行一次克隆。
5、一个线程可以控制和操作同一个进程里的其他线程,进程只能操作子进程。
6、一个主线程改变,可能会影响其他进程,改变父进程不会影响子进程。
多进程:计算密集型任务:用CPU、计算。
孤儿进程:一个父进程退出,子进程还在运行,那么这个子进程就会成为孤儿进程
僵尸进程:就是当子进程已经退出,而父进程还处在睡眠状态,此时就处于僵程inc
多线程:当IO阻塞多的时候,就可以启用多线程去加快速度。
python中多进程用的比多线程多。
多线程比多进程消耗快,其他语言优先选用多线程,多线程切换快。
一号线程请求,等待cpu处理,遇到阻塞状态就立马释放,二号线程就进行请求。 # (如果计算量大的话,GIL不会阻塞不会释放),那这样的多线程没用。
6. Python的GIL是什么
GIL称Gloabal interpreter Lockjli全局解释器锁:是CPython中遗留的问题,它保证了同一时刻同一个进程中只有一个线程可以执行代码(运行)。每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
GIL最基本的行为只有下面两个:
采用多线程:
1. 当前执行的线程持有GIL
2. 当线程遇到io阻塞时,会释放GIL
3、 时间片到也会释放 由于GIL锁的限制,所以多线程不适合计算型任务,而更适合IO型任务。
7. 什么是协程
协程:协程是一种用户态的轻量级线程,协程的调度完全由用户控制。是一种异步IO。
线程有自己的上下文,切换受系统控制;而协程有自己的上下文,但是其切换由用户控制,由当前协程切换到其他协程由当前协程来控制
缺点:无法利用多核资源。
8. Flask和django的区别
Flask:小巧、灵活,让程序员自己决定定制哪些功能,非常适用于小型网站。
Django:大而全,功能极其强大,是Python web框架的先驱,用户多,第三方库极其丰富。非常适合企业级网站的开发。
Django和Flask之间的主要区别在于Django提供了功能齐全的Model–View–Controller框架。其目的是简化网站开发过程。它依靠更少的代码,可重用的组件以及快速的开发。
另一方面,Flask是基于做好一件事的概念的微框架。它不提供ORM,仅提供一组用于Web开发的基本工具。
flask: vs django
微框架、"轻" 重(下载就继承了很多东西)
灵活、自由、可扩展性强 固定样式
9. 项目相关 流程 虚拟环境 requestsss对象 使用模块
使用venv模块创建虚拟环境:
一、在Windows中:
先在/d/项目/code进行git:
①创建项目目录
mkdir hyrz_flask YYJ@LAPTOP-I0JMQO8C MINGW64 /d/项目/code $ mkdir hyrz_flask YYJ@LAPTOP-I0JMQO8C MINGW64 /d/项目/code (master) $ cd hyrz_flask
②进入 hyrz_flask目录,创建虚拟环境
python -m venv myvenv
myvenv为虚拟环境的目录名字,执行完毕之后当前路径下会有一个myvenv文件夹。
③进入myvenv/Scripts目录:虚拟环境的pip和python等执行脚本就放在这下面 。
cd Scripts/
④进入虚拟环境::每个都有myvenv标志 ,表示你已经进入虚拟环境
YYJ@LAPTOP-I0JMQO8C MINGW64 /d/项目/code/hyrz_flask/myvenv/Scripts (master)$ source activate (myvenv)
在Linux中:
进入/lianxi 文件中:
①创建项目目录:mkdir hryz-flask
[root@localhost lianxi]# mkdir hryz-flask
② 进入 hyrz_flask目录,创建虚拟环境
[root@localhost lianxi]# cd hryz-flask
创建虚拟环境:python3 -m venv myvenv
[root@localhost hryz-flask]# python3 -m venv myvenv [root@localhost hryz-flask]# ls myvenv
③进入myvenv/bin目录
cd myvenv/ [root@localhost hryz-flask]# cd myvenv/ [root@localhost myvenv]# ls bin include lib lib64 pyvenv.cfg cd bin [root@localhost myvenv]# cd bin [root@localhost bin]# ls activate activate.fish easy_install-3.6 pip3 python activate.csh easy_install pip pip3.6 python3
④进入虚拟环境
[root@localhost bin]# source activate
进入虚拟环境成功的标志:(myvenv) [root@localhost bin]# :前面含有myvenv标志
10. 深浅拷贝 原理 现象
浅拷贝(shallowCopy):只是增加(复制)了一个指针指向已存在(某个对象)的内存地址,而不复制对象本身,新旧对象还是共享同一块内存(分支)。
- 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
- 如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
浅拷贝的实现方式:
1、使用Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
注意:当object只有一层的时候,是深拷贝。
2、Array.prototype.concat(),修改新对象会改到原对象:
3、Array.prototype.slice(),同样修改新对象会改到原对象
Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
深拷贝(deepCopy)会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)。
- 拷贝第一层级的对象属性或数组元素
- 递归拷贝所有层级的对象属性和数组元素
- 深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
引用深拷贝是为了在改变新的数组(对象)的时候,不改变原数组(对象)。
深拷贝的实现方式:JSON.parse(JSON.stringify()),用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
11. Python的字典和列表的实现原理
在Python中,字典是通过散列表或说哈希表实现的。字典也被称为关联数组,还称为哈希数组等。也就是说,字典也是一个数组,但数组的索引是键经过哈希函数处理后得到的散列值。哈希函数的目的是使键均匀地分布在数组中,并且可以在内存中以O(1)的时间复杂度进行寻址,从而实现快速查找和修改。
列表是一个线性的集合,它允许用户在任何位置插入、删除、访问和替换元素。列表实现是基于数组或基于链表结构的。当使用列表迭代器的时候,双链表结构比单链表结构更快。有序的列表是元素总是按照升序或者降序排列的元素。
Python中的列表是由对其它对象的引用组成的连续数组。指向这个数组的指针及其长度被保存在一个列表头结构中。这意味着,每次添加或删除一个元素时,由引用组成的数组需要该标大小(重新分配)。Python在创建这些数组时采用了指数分配,所以并不是每次操作都需要改变数组的大小。但是,也因为这个原因添加或取出元素的平摊复杂度较低。
12. Python的异常处理 基本正则
python遇到异常就会退出整个程序,对于特定的场景下,如果有异常发生不退出程序,或者发生了异常做特殊处理。就要引用python的异常机制。
①NameError 标识符找不到,没有被定义。
②ZeroDivisionError 除数为0异常
③IndexError 下标错误
④KeyError:关键字错误
⑤AttributeError 属性不正确
⑥ValueError参数传递类型不正确
⑦ AssertionError 断言异常,常常用在测试。
⑧ IndentationError 缩进错误
13. Python面向对象 经典类和新式类的区别(多重继承算法 经典类---深度优先 新式类—c3算法) 用过的魔术方法 __init__?
经典类新式类在类型上的区别:
① 经典类: 所有的类都是classobj类型,而类的实例都是instance类型。
类与实例只有通过__class__属性进行关联。
② 新式类 :类实例的类型是这个实例所创建自的类(通常是和类实例的__class__相同)。
继承顺序上的区别 ---多重继承。
经典类:深度优先算法。
新式类(python3):c3算法。
c3算法:首先将自身类加入本序列,然后对继承序列的元素依次判断。若某个元素不在其他序列,或者他是所有继承序列的第一个,那么把这个元素提取到本序列。
__new__(创建实例化对象)
__init__(初始化实例化对象)
__call__ :把实例化后的对象当做函数,自动调用
14. 什么是装饰器?装饰器的作用
装饰器的本质就是闭包函数。
装饰器.只能装饰callable对象。
装饰器作用:在不改变函数或者类的源代码基础上,添加额外功能。
装饰器:统计运行时间装饰器、记录日志的装饰器。