1、python是什么?
解释性语言、高级语言、开源、简洁、方便、容易扩展
2、可变类型与不可变类型
可变类型:list、dict、可变集合set
不可变类型:数字,str,tuple元组,frozenset (不可变的类型都可以被hash哈希)
内存中的那块内容(value)是否可变
3、深浅copy
浅拷贝。增加一个指针,指向所复制的对象,共用一块内存
深拷贝。增加一个指针,并且开辟了新的内存,这个增加的指针指向这个新的内存
简单地说,浅拷贝只拷贝一层(如果有嵌套),深拷贝拷贝所有层。
4、*args与**kwargs
*args:位置参数,元组,('alex',18)
**kwargs:关键字参数,字典, {'name'='alex','age'=18} 关键字参数一定要放在最后面
5、闭包
内部函数对外部函数,作用域里变量(非全局变量),的引用,则称内部函数为闭包。
闭包的意义:返回函数对象+一层作用域
该函数无论在何处调用,优先使用,自己外层包裹的作用域
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():
pass
7、生成器
延迟操作,需要的时候才产生结果,而不是立即产生结果
在每次调用next()的时候执行,遇到yield语句返回
创建生成器的两种方式:
- li = [i for i in range(100)]
- yield方法
8、range-and-xrange
py2:
range() 生成的是列表
xrange() 生成的是一个生成器
py3:
range() 就是一个生成器
xrange() 没了
9、迭代器
不是一次性把数据加载到内存,而是被next()函数调用,不断返回下一个数据
可for循环的数据类型:集合数据类型+生成器
list,tuple,dict,set,str + generator
10、经典类、新式类
经典类:深度优先,python2中
新式类:广度优先,Python3中
11、继承、多态、封装
-
继承:类与类之间关系,解决代码重用问题 。重用父类的属性与方法
-
多态:同一类事物多种形态 。一个接口,多种形态
不应关注对象的类型本身,而是它如何使用的
鸭子类型:如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子 -
封装:私有化的属性,私有化的方法,封装起来,外部无法调用
双下划线__foo
12、classmethod,staticmethod,property
- property:特性 (统一访问 原则)
把类的方法转换为属性,直接 alex.bmi 调用
@property
def bmi(self):
return self.weight / (self.height ** 2)
- staticmethod 静态方法 (普通函数 ) 绑定到对象上
类内的函数实例化---> 普通函数 。 (类和对象都可以使用)
@classmethod
def from_conf(cls):
obj = settings.name,
return obj
- classmethod 类方法 (def foo(cls)) 绑定到类上
将cls 类本身当做参数传入,直接用类来调用函数,而不用借助类实例
优雅地实现某个类的实例的构造
13、 new, __init__区别
创建一个新实例时调用__new__ , __new__在 init__之前被调用
初始化一个实例时调用__init
14、单例模式
单例模式设计的类,每次只能实例化1个对象
方式2: new _instance
class Single(object):
_instance = None
def __new__(cls,*args,**kwargs):
if not _instance:
cls._instance = super(Single,cls).__new__(cls,*args,**kwargs)
return cls._instance
15、反射
以“字符串”形式,操作对象的相关属性或方法。
hasattr, getattr, setattr, delattr
ret = getattr(obj,'get_file')() # 反射 obj是实例对象,name是方法
16、GIL
GIL:全局解释器锁(cpython解释器), 同一时刻,在cpu只能有一个线程执行
C语言解决多线程下的GIL问题
17、协程
协程:轻量级的线程,用户程序自己控制调度的
单线程下的并发, 遇到I/O阻塞,多个任务,自动切换
gevent模块实现
import gevent
def eat():
gevent.sleep(2) # 遇到阻塞会自动切换任务
def play():
gevent.sleep(3)
g1 = gevent.spawn(eat)
g2 = gevent.spawn(play)
g1.join()
g2.join()
18、进程,线程 (I/O密集型)
from multiprocessing import Process
from threading import Thread # 子线程
def task(name):
print(name)
p = Process(target=task,args=('子进程',))
p = Thread(target=task,args=('子线程',))
p.start() # 给os发个信号
p.join() # 父进程等待子进程执行完,才执行
19、僵尸进程,孤儿进程,守护进程
- 僵尸进程
子进程退出,父进程没有回收子进程,子进程的进程描述符仍然保存在系统中。 - 孤儿进程
父进程退出,子进程还在运行。孤儿进程将被init进程(pid=1)回收 - 守护进程
如果子进程的任务在主进程任务结束后就没有存在的必要了,那么该子进程应该在开启前就被设置成守护进程。
20、进程/线程 间同步方式
- 临界区。相当于保护区域
- 互斥量。加锁控制
from threading import Thread,Lock,RLock
mutexA=Lock()
mutexB=Lock()
mutexA=mutexB=RLock()
#一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,
# 这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止
mutexA.acquire()
mutexA.release()
- 信号量。PV操作--改变信号量的值 S+1+1+1-1-1-1
信号量也是一把锁,可以指定信号量为5,
互斥锁同一时间只能有一个任务抢到锁去执行
信号量同一时间可以有5个任务拿到锁去执行
解析
Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
- 事件Event。相当于通知操作
from threading import Thread, Event
import time
event = Event()
def conn():
event.wait() # 默认是False阻塞中, 等变为True 程序放行
def check():
time.sleep(5)
event.set() # Event对象 的信号标志设置未True
t1 = Thread(target=conn)
t2 = Thread(target=check)
t1.start()
t2.start()
21、整数对象池
- 小整数对象池。对小整数的定义是 [-5, 257) 这些整数对象是提前建立好的,不会被垃圾回收
- 大整数对象池。不共用内存,引用计数为0,销毁
22、python垃圾回收机制 Garbage collection(GC)
- 引用计数为主。当引用计数为0,该对象的生命就结束了
- 标记-清除。解决循环引用的问题
- 隔代回收为辅。内存块根据存活时间分为'代',gc的频率随着'代'的存活时间的增大而减小
https://www.cnblogs.com/pinganzi/p/6646742.html http://python.jobbole.com/82061/
23、网络编程
# 服务端
import socket
from threading import Thread
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 端口占用
server.bind(('127.0.0.1', 9994))
server.listen(5)
while True:
conn, addr = server.accept()
t = Thread(target=handle,args=(conn,))
t.start()
conn.close()
server.close()
def handle(conn):
data = conn.recv(1024)
conn.send(data)
# 客户端
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 9994))
while True:
data = input('>>>').strip()
client.send(data.encode('utf-8'))
ret = client.recv(1024)
print('from server:', ret.decode('gbk')) # windows gbk编码
client.close()