一、Python基础
1、什么是python?使用python有什么好处?
python是一种编程语言,它有对象、模块、线程、异常处理和自动内存管理。它简洁,简单、方便、容易扩展、有许多自带的数据结果,而且它开源
Python是一种解释性语言,它的源代码可以直接运行,Python解释器会将源代码转换成中间语言,之后再翻译成机器码再执行
2、可变类型与不可变类型
可变类型:list、dict、可变集合set
不可变类型:数字,str,tuple元组,frozenset
内存中的那块内容(value)是否可变
可直接在原来的地址,修改
不可变的类型都可以被hash哈希
3、深浅copy
对不可变类型进行copy的话,都是深copy
对于可变类型进行copy的话,一般都是浅copy
浅拷贝只是增加了一个指针指向所复制的对象,共用一块内存
深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存,
In [42]: li = [1,2,3,[4,5]]
In [43]: li2 = copy.copy(li)
In [44]: li3 = copy.deepcopy(li)
In [45]: li[-1][-1] = "222"
In [46]: li
Out[46]: [1, 2, 3, [4, '222']]
In [47]: li2
Out[47]: [1, 2, 3, [4, '222']]
In [48]: li3
Out[48]: [1, 2, 3, [4, 5]]
简单来说,如果有嵌套的话,浅copy只复制第一层,深copy会复制所有的
4、range-and-xrange
py2:
range() 生成的是列表
xrange() 生成的是一个生成器
py3:
range() 就是一个生成器
xrange() 没了
5、闭包
def func():
def inner():
print('aaaa')
return inner
func()() # aaaa
内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。
闭包的意义:返回函数对象+一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
6、装饰器
调用装饰器其实是一个闭包函数,
不修改函数的代码与修饰方式,为其他函数添加附加功能
比如:插入日志、性能测试、事物处理、缓存、权限验证等
# 装饰器
import time
def login(func):
def inner():
start_time = time.time()
func()
end_time = time.time()
print("fun 执行时间",end_time-start_time)
return inner
@login
def test():
for i in range(10000):
for j in range(10000):
pass
print('test函数执行')
test()
# test函数执行
# fun 执行时间 2.0163347721099854
7、生成器
延迟操作,需要的时候才产生结果,而不是立即产生结果
在每次调用next()的时候执行,遇到yield语句返回
创建生成器的两种方式:
li = [i for i in range(100)]、yield方法
8、迭代器
for循环的数据类型:集合数据类型+生成器
list,tuple,dict,set,str + generator
不是一次性把数据加载到内存,而是被next()函数调用,不断返回下一个数据
9、*args与**kwargs
*args:位置参数 ('alex',18)
**kwargs:关键字参数 {'name'='alex','age'=18} 关键字参数一定要放在最后面
二、面向对象
1、经典类、新式类
经典类:深度优先,python2中
新式类:广度优先,Python3中
2、继承、多态、封装
(1)继承:类与类之间关系,Cat类是动物类,解决代码重用问题
重用 父类的属性与方法
def __init__(self, name, life_value, aggresivity, weapon):
super().__init__(name, life_value, aggresivity,) # python3格式
self.weapon = weapon
def attack(self, enemy):
super().attack(enemy)
(2)多态:同一类事物多种形态
一个接口,多种形态
不应关注对象的类型本身,而是它如何使用的
鸭子类型:如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’
(3)封装
私有化的属性,私有化的方法,封装起来,外部无法调用 双下划线__foo
3、classmethod,staticmethod,property
(1)property:特性 (统一访问 原则)
@property
def bmi(self):
return self.weight / (self.height ** 2)
把类的方法转换为属性,直接 alex.bmi 调用
(2)staticmethod 静态方法 (普通函数 ) 绑定到对象上
类内的函数实例化---> 普通函数 。 (类和对象都可以使用)
@classmethod
def from_conf(cls):
obj = settings.name,
return obj
(3)classmethod 类方法 (def foo(cls)) 绑定到类上
将cls 类本身当做参数传入,直接用类来调用函数,而不用借助类实例
优雅地实现某个类的实例的构造
4、 new.init区别,如何实现单例模式
创建一个新实例时调用new new()在 init()之前被调用
初始化一个实例时调用init
单例模式设计的类只能实例化1个对象
# 方式1 python模板自带单例模式
# admin.py
class Admin(object):
def register(self):
pass
site = Admin()
# test.py
from admin import site
site.register()
# 方式2 __new__ _instance
class Single(object):
_instance = None
def __new__(cls,*args,**kwargs):
if not cls._instance:
cls._instance = super(Single,cls).__new__(cls,*args,**kwargs)
return cls._instance
5、反射
“字符串”形式,操作对象的相关属性或方法。
hasattr, getattr, setattr, delattr
ret = getattr(obj,'get_file')() # 反射 obj是实例对象,name是方法
三、并发
1、线程、进程的区别
(1)进程:程序的运行过程, os 资源调度、分配的基本单位 os的并发
(2)线程:进程的实体, cpu 调度、分派的基本单位 进程内部的并发
区别
1、进程有独立的内存空间, 线程 共享 本进程 的内存空间
2、进程有独立的系统资源 ,线程只有(程序计数器,一组寄存器,栈) 共享本进程的资源(内存,I/O,cpu)
3、独立性:进程崩溃,不会影响其他的(健壮) 线程崩溃,本进程的全部线程死掉
4、开销:进程切换与创建 开销大于 线程的
5、线程不能独立执行 进程可以
联系
都可并发、一个进程由1or多个线程 组成、一个进程中的所有线程共享该进程全部资源
2、协程、GIL
GIL:全局解释器锁(cpython解释器), 同一时刻,在cpu只能有一个线程执行
协程:轻量级的线程,用户控制调度的
单线程下(的并发), 遇到I/O阻塞,多个任务,自动切换
3、进程同步方式
1、Event事件 。 通知操作
2、互斥量。 加锁
3、信号量。 生产者消费者模型 阻塞队列Queue
4、临界区 。保护区域
同步问题:生产者消费者模型,作者读者问题,哲学家进餐问题
4、通信方式
管道,系统IPC(消息队列,信号量,信号,共享内存),套接字,远程过程调用rpc
5、死锁
多个进程运行,争夺资源,一种僵局;没有外力,进程,无法继续执行
导致死锁的原因:循环等待、不可抢占、占有且等待、互斥
死锁处理:
1、预防 :破坏4个条件
2、避免:银行家算法
3、检测:算法检测,清除死锁
4、解除: 检测到,撤销进程or剥夺资源
6、select、poll和epoll (I/O多路复用)
可以监视多个描述符
一个描述符就绪,通知应用程序,执行读or写操作
(1)select :
把文件描述符 fd 集合maxSize=1024,用户态copy到内核态 开销大,在内核,遍历所有fd
(2)poll:
改善了连接数,不断轮询,fd集合 每次都copy到内核态
(3)epoll:
linux下的多路复用I/O接口, 只copy一次,只告知 ,刚变为就绪状态的fd
四、mysql数据库
1、索引
B+数:二叉树-->平衡二叉树-->B数
一个排序好,数据结构 (协助快速查询data) 范围查询
create index ix_age on t1(age);
create index 索引名1,索引名2 on 表名('字段1','字段2')
(1)什么时候用?
经常 select查询、表记录超多
经常需要搜索的列、主键列、连接的列(外键)、范围查找 age in [20,40]、排序的列 salary、where上的列
(2)什么时候不用?
经常update,delete,insert 表记录少
不经常使用的列 addr,数据值很少的列 blog,文本,image,bit 修改>查询的
2、存储过程
相当于 函数,封装了,一系列,可执行的sql语句,存放在mysql中
直接调用它的名称
create procedure p1()
BEGIN
select * from blog;
INSERT into blog(name,sub_time) values("xxx",now());
END
优点:网络传输量小,程序与slq解耦
缺点:程序猿拓展功能不方便
3、数据库引擎
INNODB 支持事务,外键,行锁, 查表总行数,全表扫描
MYISAM不支持事务,不支持外键,表锁(插入data,锁定这个表),查表总行数,不需要全表扫描
4、redis
key-value数据库 ,经常用的data放在redis
性能极高,支持多种数据类型 ,放在内存中 (必要时可以写入硬盘)
五、网络
1、http常用的状态码
200:请求成功 OK
202:服务器接受请求,尚未处理
302:重定向
304 :上次的文档,已被缓存, 还可继续使用
400:客户端请求语法or参数错误
403:服务器收到请求,拒绝提供服务,找不到cookie
404:客户端请求的资源url不存在
500: 服务器的程序出现错误
503:服务器当前时间不能处理客户端的请求,一段时间后恢复
2、HTTP请求方式
HTTP1.0 GET/HEAD/POST
HTTP1.1 PUT/DELETE/CONNECT/OPTIONS/TRACE
3.GET/POST区别
(1)get提交的数据放在url后 /?name=alex&age=18 http请求头
post的数据放在http报请求体
(2)GET的数据大小有限制,POST没有限制
(3)GET方式会带来安全问题,在url出现信息,可能获得username password
(4)在服务端 获取请求数据方式不同
4、http请求头,请求体
协议版本,状态码,状态码原因 HTTP /1.1 200 OK
Cookie:
Content-Language
Content-Type 文本类型
Content-Length 请求体长度
User-Agent: 浏览器的身份标识,类型,手机端or电脑端
Date:时间
请求体
5、TCP/UDP区别 (运输层)
1、TCP 传输控制协议,面向连接的,可靠的,数据流传输 ,注重data安全性,传输慢,面向字节流
2、UDP用户数据报文协议,非面向连接的,不可靠,数据流传输, data传输快,安全性一般,面向报文
python部分
4、深浅拷贝
浅拷贝只是增加了一个指针指向一个存在的地址,
深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存,
简单地说,浅拷贝只拷贝一层(如果有嵌套),深拷贝拷贝所有层。
In [42]: li = [1,2,3,[4,5]]
In [43]: li2 = copy.copy(li)
In [44]: li3 = copy.deepcopy(li)
In [45]: li[-1][-1] = "222"
In [46]: li
Out[46]: [1, 2, 3, [4, '222']]
In [47]: li2
Out[47]: [1, 2, 3, [4, '222']]
In [48]: li3
Out[48]: [1, 2, 3, [4, 5]]
7、闭包
内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
def func():
def inner():
print('aaaa')
return inner
func()() # aaaa
6、装饰器
调用装饰器其实是一个闭包函数,为其他函数添加附加功能,不修改被修改的源代码和不修改被修饰的方式,装饰器的返回值也是一个函数对象。
比如:插入日志、性能测试、事物处理、缓存、权限验证等,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
# 装饰器
import time
def login(func):
def inner():
start_time = time.time()
func()
end_time = time.time()
print("fun 执行时间",end_time-start_time)
return inner
@login
def test():
for i in range(10000):
for j in range(10000):
pass
print('test函数执行')
test()
# test函数执行
# fun 执行时间 2.0163347721099854
1、什么是python?使用python有什么好处?
python是一种编程语言,它有对象、模块、线程、异常处理和自动内存管理。它简洁,简单、方便、容易扩展、有许多自带的数据结果,而且它开源
Python是一种解释性语言,它的源代码可以直接运行,Python解释器会将源代码转换成中间语言,之后再翻译成机器码再执行
3、数组和元祖之间的区别是什么?
数组和元祖之间的区别:数组内容可以被修改,而元祖内容是只读的,不可被修改的,另外元祖可以被哈希,比如作为字典的key
5、os与sys区别:
os是模块负责程序与操作系统的交互,提供了访问操作系统底层的接口
sys模块是负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控Python时运行的环境
15、range-and-xrange
py2:
range() 生成的是列表
xrange() 生成的是一个生成器
py3:
range() 就是一个生成器
xrange() 没了
21、什么是pickling和unpickling?
Pickle模块读入任何python对象,将它们转换成字符串,然后使用dump函数将其转储到一个文件中——这个过程叫做pickling
反之从存储的字符串文件中提取原始python对象的过程,叫做unpickling
8、迭代器与生成器
生成器:Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处。
这里,最难理解的就是generator和函数的执行流程不一样。
函数是顺序执行,遇到return语句或者最后一行函数语句就返回。generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时从上次返回的yield语句处继续执行。
迭代器
可以直接作用于for
循环的数据类型:
- 一类是集合数据类型,如
list
、tuple
、dict
、set
、str
等; - 一类是
generator
,包括生成器和带yield
的 generator function。
不是一次性把数据加载到内存,而是被next()函数调用,不断返回下一个数据
9、classmethod,staticmethod,property
类方法:将类的函数转换成类方法,函数上装饰@classmethod会将函数的自动传值参数改成cls
静态方法:此方法相当于给类扩展一个功能,将类内的函数实例化,给类或对象使用,此时类内的函数就是普通函数,不管是类还是实例化的对象都可以使用
实例化:类的实例化就会产生一个实例(对象),可以理解为类()把虚拟的东西实例化,得到具体存在的值
10、 new.init区别,如何实现单例模式,有什么优点
__new__是一个静态方法,__init__是一个实例方法
__new__返回一个创建的实例,init__什么都不返回
new__返回一个cls的实例时后面的__init__才能被调用
当创建一个新实例时调用__new,初始化一个实例时调用__init
_new_()在 _init_()之前被调用,用于生成实例对象。利用这个方法和类的属性的特点可以实现设计模式的单例模式。
单例模式是指创建唯一对象,单例模式设计的类只能实例,实例化1个对象
class Singleton(object):
__instance=None
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if Singleton.__instance is None:
Singleton.__instance=object.__new__(cls,*args,**kwargs)
return Singleton.__instance
2. python面向对象中的反射:
通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
11、多进程,多线程,协程,GIL
GIL:全局解释器锁,是锁在cpython解释器上,导致同一时刻,同一进程只能有一个线程被执行
多进程:多进程模块multiprocessing来实现,cpu密集型,IO计算型可以用多进程
多线程:多线程模块threading来实现,IO密集型,多线程可以提高效率
协程:依赖于geenlet,对于多线程应用。cpu通过切片的方式来切换线程间的执行,遇到IO操作自动切换,线程切换时需要耗时,
而协成好处没有切换的消耗,没有锁定概念。
进程:是资源管理单位,进行是相互独立的,实现并发和并发
线程:是最小的执行单位,线程的出现为了降低上下文切换的消耗,提供系统的并发性
12、IO多路复用/异步非阻塞
IO多路复用:通过一种机制,可以监听多个描述符 select/poll/epoll
select:连接数受限,查找配对速度慢,数据由内核拷贝到用户态
poll:改善了连接数,但是还是查找配对速度慢,数据由内核拷贝到用户态
epoll:epoll是linux下多路复用IO接口,是select/poll的增强版,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率
异步非阻塞:异步体现在回调上,回调就是有消息返回时告知一声儿进程进行处理。非阻塞就是不等待,不需要进程等待下去,
继续执行其他操作,不管其他进程的状态。
14、PEP8规范,规范的好处是什么?
1.缩进:4个空实现缩进,尽量不使用Tab
2.行:没行最大长度不超过79,换行可以使用反斜杠
3.命名规范:
4.注释规范:
16、with上下文机制原理
enter_和_exit,上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象类中声明_enter_和_exit_方法,
使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须收到干预
17、经典类、新式类
经典类遵循:深度优先,python2中
新式类遵循:广度优先,Python3中
25、Python都有哪些自带的数据结构?
可变:列表 字典
不可变: 数字 字符串 元祖
26、命名空间?
在python中,所有的名字都存在于一个空间中,它们在改空间中存在和被操作——这就是命名空间,它就好像一个盒子,在每个变量名字都对应装着一个对象,
当查询变量的时候,会从该盒子里面寻找相应的对象
28、*args与**kwargs
*args代表位置参数,它会接收任意多个参数并把这些参数作为元祖传递给函数。
**kwargs代表的关键字参数,返回的是字典,位置参数一定要放在关键字前面
7.索引B+树
B+树(数据结构,平衡树,根节点,子节点,数据) 索引能够让数据库查询数据的速度上升,而使写入数据的速度下降, 因为平衡树这个结构必须一直维持在一个正确的状态, 增删改数据都会改变平衡树各节点中的索引数据内容,破坏树结构, 因此,在每次数据改变时, DBMS必须去重新梳理树(索引)的结构以确保它的正确,这会带来不小的性能开销, 也就是为什么索引会给查询以外的操作带来副作用的原因。
8.哈希表
(Hash Table,又称为散列表),是一种线性表的存储结构。通过把每个对象的关键字k作为自变量,通过一个哈希函数h(k),将k映射到下标h(k)处,并将该对象存储在这个位置。
例如:数据集合{1,6,7,9},假设存在哈希函数h(x)使得h(1) = 0, h(6) = 2, h(7) = 4, h(9) = 5,那么这个哈希表被存储为[1,None, 6, None, 7, 9]。
当我们查找元素6所在的位置时,通过哈希函数h(x)获得该元素所在的下标(h(6) = 2),因此在2位置即可找到该元素。