本片文章部分参考地址:http://www.javashuo.com/article/p-xrchifwe-c.htmlpython
python是动态解释性的强类型定义语言mysql
强类型:不容许不一样类型相加。例如:整形+字符串会报类型错误。linux
动态:不使用显示数据类型声明,且肯定一个变量的类型是在第一次给它赋值的时候。程序员
脚本语言:通常是解释性语言,运行代码只须要一个解释器,不须要编辑。web
Python面试
魔法方法:算法
__init__
用来作变量初始化 或 赋值 操做,在类实例化对象的时候,会被自动调用sql
__new__
返回父类的new出来的实例self,或直接是object的new出来的实例self–>比init先调用生成实例供init用shell
__str__
return 一个数据,而且只有self一个参数,当在类的外部 print(对象) 则打印这个数据数据库
__del__
析构函数,当删除对象时,python解释器也会默认调用
python面向对象特性:
封装: 封装就是把类中的属性和方法定义为私有的,python会自动将其转换为_类名__属性名(方法名)的格式,子类没法对进行修改
继承: 关于__mro__
方法解析顺序,新式类是广度优先查找,经典类是深度优先,
多态: python弱化了多态概念:无论对象类型,只要对象有该方法就可执行。关于面向对象的多态理解,建议参考鸭子类型。
------ 鸭子类型: Python在使用传入参数的过程当中不会默认判断参数类型,只要参数具有执行条件就能够执行
新式类和经典类:
2.2出现新式类,3全是新式类,新式类是广度优先查找,经典类是深度优先;
重点: 新式类的广度优先解决了经典类的mro
查找忽略同一级别的属性的bug
使用dir()
方法也能够看出新式类中定义不少新的属性和方法
(new,call,dict模块\属性\方法\doc,class对象属于的类,...等
),
而经典类好像就2个(doc文档,module属于哪一个模块
):
静态方法和类方法和实例方法
\ | 实例方法 | 类方法 @classmethod传cls | 静态方法@staticmethod不传self和cls |
---|---|---|---|
a = A() | a.foo(x) | a.class_foo(x) | a.static_foo(x) |
A | 不可用 | A.class_foo(x) | A.static_foo(x) |
Python自省(特性)
自省就是面向对象的语言经过必定的机制查询到对象的内部结构
好比dir(对象), 对象.__dict__
Python元类 type(future_class_name, future_class_parents元祖, uppercase_attr字典)
#返回一个类
建立类的类,元类要继承type,建立一个类的时候,他尚未在内存中生成,直到被调用:
python作了以下操做:依次在—>当前类中–>父类中–>模块层次中–>查看有没有__metacalss__
属性,都没有就会调用内置元类type建立这个类对象。
ORM(对象关系映射)核心:数据描述符和元类
优缺点:
1)只须要面向对象编程, 不须要面向数据库编写代码,对数据库的操做都转化成对类属性和方法的操做.不用编写各类数据库的sql语句.
2)实现了数据模型与数据库的解耦, 屏蔽了不一样数据库操做上的差别.不在关注用的是mysql,oracle…等.经过简单的配置就能够轻松更换数据库, 而不须要修改代码.
3)在映射过程当中有性能缺失,面向对象编程到sql语句之间的映射须要过程时间,形成性能缺失
定义一个ORM
:
class Field: pass class CharField(Field): '''数据描述符, 好处在于能够在各方法中校验传入值的合理性''' def __init__(self, col_name, max_length): if col_name is None or not isinstance(col_name, str): raise ValueError("col_name must be given as str") if max_length is None or not isinstance(max_length, numbers.Integral): raise ValueError("max_length must be given as int") self._col_name = col_name self._max_length = max_length def __get__(self, instance, owner): # return getattr(instance, self._col_name) return instance.fields[self._col_name] def __set__(self, instance, value): # 这里若是col_name和数据描述符对应的名字同样的话,如name=CharField(col_name="name",10) # 用setattr(instance, self._col_name, value)即user.name=value会再次进入此__set__方法,致使无限递归 instance.fields[self._col_name] = value class ModelMetaClass(type): '''元类''' def __new__(cls, cls_name, base_class, attrs): if cls_name == "Model": return super().__new__(cls, cls_name, base_class, attrs) fields = {} for k, v in attrs.items(): if isinstance(v, Field): fields[k] = v attrs["fields"] = fields _meta = {} attrs_meta = attrs.get("Meta", None) if attrs_meta is not None and isinstance(attrs_meta, type): _meta["tb_name"] = getattr(attrs_meta, "tb_name", cls_name) del attrs["Meta"] else: _meta["tb_name"] = cls_name.lower() attrs["_meta"] = _meta return super().__new__(cls, cls_name, base_class, attrs) class Model(metaclass=ModelMetaClass): # 指定要使用的元类 def __init__(self, **kwargs): self.fields = {} for k, v in kwargs.items(): setattr(self, k, v) # def more_func(self): # pass class User(Model): name = CharField(col_name="name", max_length=10) sex = CharField(col_name="sex", max_length=1) age = IntField(col_name="age", min_length=1, max_length=10) class Meta: tb_name = "User"
该模式的主要目的是确保某一个类只有一个实例存在。当你但愿在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。(好比系统回收站)
# __new__方法实现 class Singleton(object): def __new__(cls,*args,**kw) if not hasattr(cls,'_instance') cls._instance = super(Singleton,cls).__new__(cls,*args,**kw) return cls._instance # 建立一个类的实例或者继承这个类的就是单例类
# 装饰器方法 def singleton(cls,*args,**kwargs): instances={} def getinstance(): if cls not in instances: instances[cls]=cls(*args,**kwargs) return instances[cls] return getinstance @singleton class MyClass(object): pass # 还有import 一个类的实例,就是自然的单例
核心的思想是: 经过传递给类或函数某种产品的信息来建立产品并返回。当咱们想获得产品a对象,只需把产品a的名字传递给工厂函数就能获得产品a对象。
import abc class A(object): def __init__(self, product_type): self.product_type = product_type def __str__(self): return 'product %s' % self.product_type class B(object): def __init__(self, product_type): self.product_type = product_type def __str__(self): return 'product %s' % self.product_type class Abstract_factory(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def yield_product(self): pass class Factory_a(Abstract_factory): def yield_product(self): return A('A') class Factory_b(Abstract_factory): def yield_product(self): return B('B') def factory(product_type): if product_type == 'A': return Factory_a() if product_type == 'B': return Factory_b() if __name__ == '__main__': factory_a = factory('A') a = factory_a.yield_product() factory_b = factory('B') b = factory_b.yield_product() print(a) print(b)
Py2和Py3区别
区别 | py2 | py3 |
---|---|---|
print是一个打印语句 | 函数 能够多个位置的参数 | |
input | raw_input获得str | input获得str |
整除 | 3/2 -->1 但3/2.0–>1.5 | 3//2 获得1 |
range | range(4)–>[0,1,2,3]列表 | range(4) 获得可迭代对象(type是对象) |
xrange | xrange(4)–>生成器 | 只有range |
unicode | 默认ASC II ,unicode() 是单独的 | 源码文件默认使用utf-8编码 |
nonlocal关键字 | 函数内变量就是局部变量 | 可声明为非局部变量,能够在外使用 |
True.False | 视为全局变量,随意赋值 | 变成关键字,指向固定对象,不能从新赋值。 |
Python中的list
是分离式的元素外置顺序表,表头区,元素区存id地址,数据区存数据能够不连续的内存
dict底层结构
为了支持快速查找使用了哈希表做为底层结构
哈希表平均查找时间复杂度为o(1)
CPython解释器使用二次探查解决哈希冲突问题
字符串处理方法
mystr.find(str, start=0, end=len(mystr)) # 有返回下标索引==无返回-1 mystr.strip() # 删除两边空白字符 mystr.splitlines() # 按行分隔成列表 mystr.split(",", 1) # 默认所有分割,1表明分割第一个 a.isalnum # 判断全是字母数字 "_".join(list) #每一个元素后面加一个字符串_变成str
赋值、浅拷贝和深拷贝
直接赋值:其实就是对象的引用(别名)。=
浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。切片,工厂函数list(), copy.copy()
深拷贝(deepcopy): copy 模块的 deepcopy 方法,彻底拷贝了父对象及其子对象。
python函数式编程 map,filter,reduce
# 高阶函数--》函数的参数可以接收别的函数。 map(lambda x: x * x, [1,3,4])) # 每一个数都平方获得一个新迭代器 filter(lambda x:x%2==1,[1,2,3,4,5,6,7]) # 过滤掉列表中的奇数,第二个参数是可迭代对象或者迭代器 reduce(lambda x, y: x+y, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5 sorted([36, 5, -12, 9, -21], key=abs[,reverse=True]) # 按绝对值大小排序 [3,4,2].sort(key=lambda x : x+1) # 对原列表更改
类装饰器:要实现init和call方法
闭包装饰器:外函数返回内函数的引用,内函数使用外函数的局部变量并调用被装饰函数
def log(func): @functools.wraps(func) # 让now函数的名字仍是原来的__name__ def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper @log # 把@log放到now()函数的定义处,至关于执行了语句:log = log(now) def now(): print('2015-3-25') # 装饰器传参 def log(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator @log('execute') # 至关于执行 now = log('execute')(now) def now(): print('2015-3-25')
垃圾回收机制
(主)引用计数(reference counting): 引用计数为0时,该对象生命就结束了。维护引用计数消耗资源,循环引用L.append(L) L一直不回收
(辅)标记清除机制(mark and sweep): 不改变真实引用计数,复制一份,若是A引用了B,将B计数-1,B也引用了A,将A也-1,这样就显示出了真是的引用计数
(辅)分代计数: 将系统中的全部内存块根据其存活时间划分为不一样的集合,每个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减少。也就是说,活得越长的对象,就越不多是垃圾,就应该减小对它的垃圾收集频率。那么如何来衡量这个存活时间:一般是利用几回垃圾收集动做来衡量,若是一个对象通过的垃圾收集次数越多,能够得出:该对象存活时间就越长。
面试回答: Python的GC模块主要运用了“引用计数”来跟踪和回收垃圾。在引用计数的基础上,还能够经过“标记-清除”解决容器对象可能产生的循环引用的问题。经过“分代回收”以空间换取时间来进一步提升垃圾回收的效率。
sys模块几个经常使用方法
OS模块几个经常使用方法
os.system(command) #函数用来运行shell命令
os.path模块:
abspath(path) #返回绝对路径
basename§ #返回路径的最后一个/后面的内容
dirname(file) #返回当前文件/的目录名 __file__也能够目录
exits(path) #测试一个目录存在与否
isabs(s) #判断一个路径是不是绝对路径
isdir(s) #判断是否是目录
isfile(path) #判断是否是文件
join(‘路径’,‘路径/文件’) #os.path.join(os.path.dirname(BASE_DIR), “logs/meiduo.log”)
globals/locals(能够变相操做代码)
实现从1-100每三个为一组分组
print([[x for x in range(1,101)][i:i+3] for i in range(0,100,3)])
单元测试
import unittest class MyTest(unittest.TestCase): # 继承自TestCase 单独运行文件 # 测试开始的方法 def setUp(self): print("setup") #测试方法 必须test_开头 能够多个 光标放在哪一个函数的内部,就执行哪一个测试方法 def test_login(self): print("test_login") # 测试结束的方法 def tearDown(self): print("teardown")
GIL全局解释器锁
同一时间只能有一个线程执行,竞争的是cpu内存资源,CPython的特色,其余解释器不存在
cpu密集型:多进程+进程池
io密集型:多线程/协程
tip:什么是Cpython==将python解释成C代码工具
进程,线程,协程,锁
fork()
能够在父进程中建立一个子进程,这样的话,在一个进程接到来自客户端新的请求时就能够复制出一个子进程让其来处理,父进程只需负责监控请求的到来,而后建立子进程让其去处理,这样就能作到并发处理。锁
线程互斥锁:当多个线程同时修改同一条数据时可能会出现脏数据,产生了互斥锁保证同一时刻只有一个线程访问数据 threading.Lock()
线程安全:由于多线程是共享系统资源的,有了互斥锁,每一个线程对数据进程操做都能获得正确的结果
避免死锁
死锁:2个线程互相等待对方的锁,互相占用着资源不释放, 某一个线程没有正常释放锁
利用上下文管理器with 自动申请并释放锁
with在执行时须要这两个方法:__enter__与__exit__
好比open就有
进程与线程的使用场景
**进程间通信 **multiprocessing中的Manager类和Pipe类和Queue类,进程池用Manager().Queue(10)
Manager().dict()
progress_dict = Manager().dict() # 传给子进程任务函数
Pipe(适用于两个进程) 管道
recevie_pipe, send_pipe = Pipe() # 传给接受和发送的任务函数
Queue(10) 消息队列
queue = Queue(10) # 传给子进程 queue.get(),queue.put()
unix进程间通讯方式(IPC)
管道pipe:两个亲戚进程
命名管道named pipe:容许不是亲戚的进程间通讯
信号signal:信号是比较复杂的通讯方式,用于通知接受进程有某种事件发生
消息队列message: 息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺
共享内存、使得多个进程能够访问同一块内存空间,是最快的可用IPC形
内存映射:内存映射容许任何多个进程间通讯,每一个进程经过把一个共享的文件映射到本身的进程地址空间来实现它
信号量: 主要做为进程间以及同一进程不一样线程之间的同步手段。
套接口: 更为通常的进程间通讯机制,可用于不一样机器之间的进程间通讯。
生成器和迭代器
__next__
和__iter__
方法的对象就是迭代器
对字典列表按年龄进行倒序排序d_list = [{'name':'a','age':18},....]
d_list.sort(key=lambda x:x['age'],reverse = True)
如何将一个可迭代对象的每一个元素变成一个字典的全部键?
{}.fromkeys(['jim','han'],21) # output:{'jim': 21, 'han': 21}
一只青蛙一次能够跳上1级台阶,也能够跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
fib = lambda n: n if n <=2 else fib(n-1) + fib(n-2)
实现删除一个 L1=[1,2,3,3,2]里面的重复元素
L2 = list(set(L1)) L2.sort(key = L1.index) # 使用列表生成时 append L2 = [] [L2.append(i) for i in L1 if i not in L2]
合并两个有序列表
def loop_merge_sort(l1, l2): tmp = [] while len(l1) > 0 and len(l2) > 0: if l1[0] > l2[0]: tmp.append(l2[0]) del l2[0] # 列表删除时间复杂度大 else: tmp.append(l1[0]) del l1[0] tmp.extend(l1) tmp.extend(l2) return tmp
# 不删除元素,时间复杂度低 def text(listone,listtwo): join_list=[] i,j=0,0 while True: if len(listone) <=i: join_list.extend(listtwo[j:]) break elif len(listtwo)<=j: join_list.extend(listone[i:]) break if listone[i]>= listtwo[j]: join_list.append(listtwo[j]) j+=1 else: join_list.append(listone[i]) i+=1 return join_list
多路复用io
其实全部的I/O都是轮询的方法,只不过实现的层面不一样罢了.
python的select模块,提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。
select
poll
epoll
适用于链接数量较多,但活动连接数少的状况 改善select三个缺点
说一些你比较经常使用linux指令
ls/ll、cd、cat、tree、touch、mkdir、rm-rf、cp、mv、ps -aux| grep xxx、kill -九、top、tar -xvf file.tar
权限 ls -l
chmod u=rw, g=x, o=r test.py
搜索文本grep grep -n ‘^a’ file.txt
查找文件:find find ./ -name ‘*.sh’
远程登陆ssh 用户名@IP
SSH(openssh-server) 是专为远程登陆会话和其余网络服务提供安全性的协议。经常使用于远程登陆,以及用户之间进行资料拷贝
远程拷贝 (前提是已经安装了openssh)若是是文件夹+-r
scp 本地文件名 远程用户名@远程ip:文件
本地上传到远程
scp 远程用户名@远程ip:远程文件 本地文件名
复制远程到本地
FileZilla 软件
能够经过图形化操做的方式进行远程主机的文件上传和下载.
vim(vi)编辑器
有命令模式、输入模式、末行模式三种模式。
命令模式:查找内容(/abc、跳转到指定行(20gg)、跳转到尾行(G)、跳转到首行(gg)、删除行(dd)、插入行(o)、复制粘贴(yy,p)
输入模式:编辑文件内容
末行模式:保存退出(wq)、强制退出(q!)、显示文件行号(set number)
在命令模式下,输入a或i便可切换到输入模式,输入冒号(:)便可切换到末行模式;在输入模式和末行模式下,按esc键切换到命令模式
快速排序:不稳定,最优O(nlogn),差O(n*n)
取第一个值为中间值,其余的与之比较,放左边和右边,再对左右两边分别排序
def quick_sort(arr): if len(arr) < 2: return arr mid = arr[0] less = [i for i in arr[1:] if i <= mid] more = [i for i in arr[1:] if i > mid] return quick_sort(less) + [mid] + quick_sort(more)
归并排序:稳定,最优O(nlogn),最差O(nlogn) 产生了多一份的空间
先拆分红最小的单元,而后两两判断合并
def merge(left, right): L,R = 0, 0 # 先考虑左边一个和右边一个进行比较 添加到新列表中 slist = [] while L < len(left) and R < len(right): if left[L] <= right[R]: slist.append(left[L]) L += 1 else: slist.append(right[R]) R += 1 slist += left[L:] slist += right[R:] return slist def merge_sort(arr): if len(arr) < 2: return arr else: mid_i = len(arr) // 2 # 分而治之 left = merge_sort(arr[:mid_i]) right = merge_sort(arr[mid:]) return merge(left, right)
插入排序: 稳定,最优O(n),差O(n*n)
认定一个值是有序的,后面的依次浮动比较前一个值,小了就交换,目的是把后面的插入到前面的有序序列
def insert_sort(arr): for i in range(1,len(arr)): j = i # 1,2,3,4 ...n-1 while j > 0: if arr[j] < arr[j-1]: arr[j], arr[j-1] = arr[j-1], arr[j] j -= 1 else: break # 希尔排序 gap = len(arr) // 2 while gap >0 : ...插入排序里面的1换成gap gap //= 2
冒泡排序: 稳定, 最优O(n),差O(n*n)
临近的两个值比较,大的放后面,第一遍的时候最后一个正确位置,第二遍时后两个都正确。。。。
def bubule_sort(arr): for i in range(len(arr)-1,0,-1) # n-1, n-2,... 2, 1 flag = False for j in range(i): if arr[j+1] < arr[j]: arr[j], arr[j+1] = arr[j+1], arr[j] flag = True if not flag: break
选择排序: 不稳定,最优最坏都是O(n*n)
假设最后一个最大,从左到右(除了最后一个)依次与最大值进行比较并交换
def selection_sort(arr): for i in range(len(arr)-1, 0, -1): # n-1, n-2,... 2, 1 for j in range(i): if arr[j] >arr[i]: array[j], array[i] = array[i], array[j] return array
堆排序[heapq模块] 不稳定,时间复杂度与归并同样 nlogn,nlogn
堆是一颗彻底二叉树:除了最后一层以外的其余每一层都被彻底填充,而且全部结点都保持向左对齐的树
最大堆:任意节点的值不大于其父亲节点的值。
最小堆:任意节点的值不小于其父亲节点的值。
堆有什么用途?
堆最经常使用于优先队列以及相关动态问题。
优先队列指的是元素入队和出队的顺序与时间无关,既不是先进先出,也不是先进后出,而是根据元素的重要性来决定的
from heapq import nsmallest def heap_sort(_list): return nsmallest(len(_list),_list)
二分查找必须是有序的序列,
def binary_find(arr, item): '''非递归''' # 定义头和尾的游标,依次进行判断进行移动游标 first,end = 0, len(arr)-1 while first <= end: mid = (first + end) //2 if item < arr[mid]: end = mid elif item > arr[mid]: first = mid + 1 else: return mid return False print(binary_find([1,2,3], 1)) def binary_search(alist, item): '''递归实现''' if len(alist) == 0: return False else: mid = len(alist)//2 if alist[mid]==item: return True else: if item < alist[mid]: return binary_search(alist[:midpoint],item) else: return binary_search(alist[midpoint+1:],item)
class Stack(object): """栈""" def __init__(self): self.items = [] def is_empty(self): """判断是否为空""" return self.items == [] def push(self, item): """加入元素""" self.items.append(item) def pop(self): """弹出元素""" return self.items.pop() def peek(self): """返回栈顶元素""" return self.items[len(self.items)-1] def size(self): """返回栈的大小""" return len(self.items)
class Queue(object): """队列""" def __init__(self): self.items = [] def is_empty(self): return self.items == [] def enqueue(self, item): """进队列""" self.items.insert(0,item) def dequeue(self): """出队列""" return self.items.pop() def size(self): """返回大小""" return len(self.items)
class Queue(object): def __init__(self): self.stack1 = [] self.stack2 = [] def append_tail(self,item): self.stack1.append(item) def del_head(self): if not self.stack2: if self.stack1: while self.stack1: item = self.stack1.pop() self.stack2.append(item) else: raise Exception('stack1 is empty') item = self.stack2.pop() return item q = Queue() q.append_tail(1) q.append_tail(2) q.append_tail(3) print(q.del_head()) # 输出先进入队列的1,