python编程遇到点困难,就是运行一串代码200毫秒接着运行下一行代码
可以用time.sleep(200):
import time
print("输出1")
time.sleep(0.2) # 200毫秒后输出2
print("输出2")
import time
import signal
def handler(signum, frame):
print("程序超时退出!")
exit(1)
signal.signal(signal.SIGALRM, handler)
signal.alarm(0.2)
start_time = time.time()
while True:
# 循环执行的代码
current_time = time.time()
if current_time - start_time > 0.2:
break
#执行下一段程序
...
89. 正则表达式匹配中(.*)和(.*?)匹配区别?
(.*)是贪婪匹配,会把满足正则的尽可能多的往后匹配
(.*?)是非贪婪匹配,会把满足正则的尽可能少匹配
import re
s= str("<a>哈哈</a><a>啦啦</a>")
res1 = re.findall("<a>(.*)</a>",s)
print(res1)
res2 = re.findall("<a>(.*?)</a>",s)
print(res2)
90. 写一段匹配邮箱的正则表达式
合法邮箱的例子:
1234@qq.com(纯数字)
wang@126.com(纯字母)
wang123@126.com(数字、字母混合)
wang123@vip.163.com(多级域名)
wang_email@outlook.com(含下划线 _)
wang.email@gmail.com(含英语句号 .)
根据对以上邮箱的观察,可将邮箱分为两部分(“@”左边和右边部分)来进行分析:
1 左边部分可以有数字、字母、下划线(_)和英语句号(.),因此可以表示成:[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*。
2 右边部分是域名,按照域名的规则,可以有数字、字母、短横线(-)和英语句号(.),另外顶级域名一般为 2 ~ 6 个英文字母(比如“cn”、“com”、“site”、“group”、“online”),故可表示为:([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}。
要注意两点:
1 考虑到匹配邮箱时字符串的一头一尾不能有其它字符,故要加上开始标志元字符 ^ 和结束标志元字符 $。
2 英语句号(.)是正则表达式的元字符,因此要进行转义(\.)。
email = /^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$/
其他内容
91.解释一下 python 中 pass 语句的作用?
92.简述你对 input()函数的理解
93.python 中的 is 和==
94. Python 中的命名空间和作用域
命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过Python字典来实现的。
命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
一般有三种命名空间:
1、内置名称(built-in names),Python语言内置的名称,比如函数名 abs、char 和异常名称BaseException、Exception 等等。
2、全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
3、局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
命名空间查找顺序:
假设我们要使用变量runoob,则 Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间。
如果找不到变量 runoob,它将放弃查找并引发一个 NameError 异常:
NameError: name 'runoob' is not defined。
命名空间的生命周期:
命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。
因此,我们无法从外部命名空间访问内部命名空间的对象。
作用域就是一个Python程序可以直接访问命名空间的正文区域。
在一个python程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。
Python的作用域一共有4种,分别是:
L(Local):最内层,包含局部变量,比如一个函数/方法内部。
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。
比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G(Global):当前脚本的最外层,比如当前模块的全局变量。
B(Built-in): 包含了内建的变量/关键字等。,最后被搜索
规则顺序: L –> E –> G –>gt; B。
在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
注意:Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,
95.三元运算写法和应用场景?
96.了解 enumerate 么?
97.列举 5 个 Python 中的标准模块
98.如何在函数中设置一个全局变量
99.pathlib 的用法举例
100.Python 中的异常处理,写一个简单的应用场景
101.Python 中递归的最大次数,那如何突破呢?
102.什么是面向对象的 mro
103.isinstance 作用以及应用场景?
104.什么是断言?应用场景?
105.lambda 表达式格式以及应用场景?
106.新式类和旧式类的区别
107.dir()是干什么用的?
108.一个包里有三个模块,demo1.py, demo2.py, demo3.py,但使用 from tools import *导入模块时,如何保证只有 demo1、demo3 被导入了。
109.列举 5 个 Python 中的异常类型以及其含义
110.copy 和 deepcopy 的区别是什么?
111.代码中经常遇到的*args, **kwargs 含义及用法。
112.Python 中会有函数或成员变量包含单下划线前缀和结尾,和双下划线前缀结尾,区别是什么?
113.w、a+、wb 文件写入模式的区别
114.举例 sort 和 sorted 的区别
115.什么是负索引?
116.pprint 模块是干什么的?
117.解释一下 Python 中的赋值运算符
118.解释一下 Python 中的逻辑运算符
119.讲讲 Python 中的位运算符
120.在 Python 中如何使用多进制数字?
121.怎样声明多个变量并赋值?
算法和数据结构
122.已知:
(1) 从 AList 和 BSet 中 查找 4,最坏时间复杂度那个大?
(2) 从 AList 和 BSet 中 插入 4,最坏时间复杂度那个大?
123.用 Python 实现一个二分查找的函数
124.python 单例模式的实现方法
125.使用 Python 实现一个斐波那契数列
126.找出列表中的重复数字
127.找出列表中的单个数字
128.写一个冒泡排序
129.写一个快速排序
130.写一个拓扑排序
131.python 实现一个二进制计算
132.有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法。
133.单链表反转
134.交叉链表求交点
135.用队列实现栈
136.找出数据流的中位数
137.二叉搜索树中第 K 小的元素
爬虫相关
138.在 requests 模块中,requests.content 和 requests.text 什么区别
139.简要写一下 lxml 模块的使用方法框架
140.说一说 scrapy 的工作流程
141.scrapy 的去重原理
142.scrapy 中间件有几种类,你用过哪些中间件
143.你写爬虫的时候都遇到过什么?反爬虫措施,你是怎么解决的?
144.为什么会用到代理?
145.代理失效了怎么处理?
146.列出你知道 header 的内容以及信息
147.说一说打开浏览器访问 百度一下,你就知道 获取到结果,整个流程。
148.爬取速度过快出现了验证码怎么处理
149.scrapy 和 scrapy-redis 有什么区别?为什么选择 redis 数据库?
150.分布式爬虫主要解决什么问题
151.写爬虫是用多进程好?还是多线程好? 为什么?
152.解析网页的解析器使用最多的是哪几个
153.需要登录的网页,如何解决同时限制 ip,cookie,session(其中有一些是动态生成的)在不使用动态爬取的情况下?
154.验证码的解决(简单的:对图像做处理后可以得到的,困难的:验证码是点击,拖动等动态进行的?)
155.使用最多的数据库(mysql,mongodb,redis 等),对他的理解?
网络编程
156.TCP 和 UDP 的区别?
157.简要介绍三次握手和四次挥手
158.什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
并发
159.举例说明 conccurent.future 的中线程池的用法
160. 说一说多线程,多进程和协程的区别。
1、进程是操作系统分配的最小单位,线程是CPU调度的最小单位,协程既不是进程也不是线程,协程仅仅是一个特殊的函数,协程和进程、线程不是一个维度的。
2、一个进程由一个或者多个线程组成,线程是一个进程中代码的不同执行路线,协程是属于一种操作,是由用户自己去操作线程的切换(在用户态进行切换),这样的话,就可以大大降低线程切换(在内核态切换)的花销。
3、切换进程需要的花销(时间、资源等)比切换线程要大,切换线程也是需要花销的,协程与进程一样,切换是存在上下文切换问题的。
4、一个进程可以包含多个线程,一个线程可以包含多个协程。
5、一个线程内的多个协程虽然可以切换,但是多个协程是串行执行的,只能在一个线程内运行,没法利用CPU多核能力。
# 多进程执行多任务
import os
import time
from multiprocessing import Pool
# multiprocessing模块提供了一个Pool进程池的方式批量创建子进程。
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(1) # 线程推迟执行的时间
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p = Pool(5) # Pool对象,参数5表示调用多少个并行进程进行程序运行,pool的默认容量为CPU的计算核数量
for i in range(10):
p.apply_async(long_time_task, args=(i,)) # p.apply_async()函数给进程池添加进程任务,它的参数包括待运行程序和程序的传入参数。
print('Waiting for all subprocess done ...')
p.close() # 对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。
p.join() # join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。
print('All subprocesses done.')
# 多线程执行多任务
import time
import threading
# threading模块
# 新线程执行的代码:
def loop():
print('thread %s is running...' % threading.current_thread().name)
# threading.current_thread()永远返回当前线程的实例
n = 0
while n < 5:
n = n + 1
print('thread %s >>> %s' % (threading.current_thread().name, n))
time.sleep(1)
print('thread %s ended.' % threading.current_thread().name)
print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread') # 用LoopThread命名子线程
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)
161. 简述 GIL
并行与并发的理解:
并发:交替处理多个任务的能力;
并行:同时处理多个任务的能力;
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力,强调的是同时.
最大的区别:是否是『同时』处理任务。
通过代码可以发现多进程可以充分使用cpu的两个内核而多线程却不能充分使用cpu的两个内核
问题:通过验证我们发现多线程并不能真正的让多核cpu实现并行。
原因:
cpython解释器中存在一个GIL(全局解释器锁),其作用就是保证同一时刻只有一个线程可以执行代码,
这造成使用多线程的时候无法实现并行。
结论:
1.在处理像科学计算这类需要持续使用cpu的任务的时候单线程会比多线程快,可以使用多进程利用多核的CPU资源。
2.在处理像IO操作等可能引起阻塞的这类任务的时候多线程会比单线程,因为遇到IO阻塞会自动释放GIL锁
解决方案法:
1:更换解释器比如使用jpython(java实现的python解释器)
2:使用多进程完成多任务的处理
162. 进程之间如何通信
Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
print('Process to write: %s' % os.getpid())
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
print('Process to read: %s' % os.getpid())
while True:
value = q.get(True)
print('Get %s from queue.' % value)
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
163.IO 多路复用的作用?
164.select、poll、epoll 模型的区别?
165.什么是并发和并行?
166.一个线程 1 让线程 2 去调用一个函数怎么实现?
167.解释什么是异步非阻塞?
168. threading.local 的作用?
内部自动为每个线程维护一个空间(字典),用于当前存取属于自己的值。保证线程之间的数据隔离。
{
线程ID: {...}
线程ID: {...}
线程ID: {...}
线程ID: {...}
}
Git 面试题
169.说说你知道的 git 命令
170.git 如何查看某次提交修改的内容