1、常用字符串格式化有哪些?并说明他们的区别
格式化操作符(%)
fotmat
2、请手写一个单例模式(面试题)
无论实例化多少次,他的对象始终是一个内存地址
单例模式,示例:
class test:
__instance = None
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if cls.__instance == None:
cls.__instance = object.__new__(cls,*args, **kwargs)
return cls.__instance
a = test()
b = test()
print(a)
print(b)
3、利用 python 打印前一天的本地时间,格式为‘2018-01-30’(面试题)
使用datetime模块
代码示例:
import datetime
now_time = datetime.datetime.now()
yes_time = now_time + datetime.timedelta(days=-1)
yes_time_nyr = yes_time.strftime('%Y-%m-%d')
print(yes_time_nyr)
4、python 中 search()和 match()的区别(面试题)
match()函数只检测RE是不是在string的开始位置匹配, search()会扫描整个string查找匹配, 也就是说match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回none
5、写一个闭包函数 clo,接收整数参数 n ,返回一个函数 foo,foo 函数的功能是把 foo 参数和 n 相乘并把结果返回。
装饰器也属于闭包函数
def clo(n):
def foo(*args):
number = 5
return number*n
return foo
print(clo(5)())
6、# 取出 html 中的歌手名和歌名
提示:<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
html = '''<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦">往事随风</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君">但愿人长久</a>
</li>
</ul>
</div>'''
使用正则re模块
import re
results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
7、请写出函数式编程 filter、map 的实例。
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]过滤出列表的所有奇数(filter)
[1,2,3,4,5]计算出每个元素的平方(map)
filter
y = filter(lambda x:x % 2 ==1, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
for i in y:
print(i)
map
s = map(lambda x:x*x,[1,2,3,4,5])
for i in s:
print(i)
8、简述 Python 垃圾回收机制
简单来说:(详细可参考baidu)
当一个对象的引用被创建或者复制时,对象的引用计数+1,当一个对象的引用被销毁时,-1
当一个对象引用计数为0时,就意味着对象已经没有被使用了,可以释放其内存了
9、用最简洁的方式生成这样一个列表【4,16,32,64,128】
print([2 ** x for x in range(2,8) if x != 3])
10、简述 python GIL 的概念, 以及它对 python 多线程的影响?
GIL本质是全局解释器锁(也是一把互斥锁),既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。
有了GIL的存在,同一时刻同一进程中只有一个线程被执行
11、写一段程序逐行读取一个文本,并在屏幕上输出
with open('test.py', 'r') as f:
while True:
content = f.readline()
print(content)
if not content:
break
12、如何用 Python 删除一个文件,创建一个文件夹
import os
删除一个文件 :os.remove
创建一个文件夹 : os.mkdir
13、什么是”并发“?什么是”并行“?
无论是并行还是并发,在用户看来都是'同时'运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务
一 并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
二 并行:同时运行,只有具备多个cpu才能实现并行
单核下,可以利用多道技术,多个核,每个核也都可以利用多道技术(多道技术是针对单核而言的)
14、描述 Event 的执行机制
Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位真,则其他线程等待直到信号接触。
Event对象实现了简单的线程通信机制,它提供了设置信号,清除信号,等待等用于实现线程间的通信。
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
15、什么是粘包,如何避免?
同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包。
黏包现象只发生在tcp协议中:
1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。
2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
我们可以借助一个模块,这个模块可以把要发送的数据长度转换成固定长度的字节。这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小,那么最终接受的数据只要达到这个值就停止,就能刚好不多不少的接收完整的数据了。
借助struct模块,我们知道长度数字可以被转换成一个标准大小的4字节数字。因此可以利用这个特点来预先发送数据长度。
16、叙述 TCP、UDP 的区别
TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。
UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)
17、叙述 OSI 七层协议是什么,三次握手,四次挥手分别是什么
三次握手
1. 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
2. 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
3. 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
四次挥手
1. 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
2. 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
3. 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
4. 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手
18、简述你对管道、队列的理解;
管道可以用于双向通信,利用通常在客户端/服务器中使用的请求/响应模型或远程过程调用,就可以使用管道编写与进程交互的程序
进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
19、编程题;写一个装饰器实现功能:打印程序的运行时间
装饰器
def wrapper(func):
def inner():
start_time = time.time()
func()
print("程序运行时间:",time.time() - start_time)
return inner
@wrapper
def test():
time.sleep(2)
test()
20、写一个简单的 Python socket 服务端和客户端
server端代码
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 9999))
sk.listen()
conn, addr = sk.accept()
conn.send('你好'.encode('utf-8'))
ret = conn.recv(1024)
print(ret.decode('utf-8'))
client端代码
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 9999))
ret = sk.recv(1024)
print(ret.decode('utf-8'))
sk.send('你也好'.encode('utf-8'))
sk.close()
21、使用 python 简单实现打印九九乘法表
优化版:使用一行代码实现九九乘法表
print('\n'.join([' '.join(['%s*%s=%-2s' % (y,x,x*y) for y in range(1,x+1)]) for x in range(1,10)]))
22、 请找出以下代码的问题。提示:5 处
#Python3 环境
class dummyclass(object):
def __init__(self):
self.is_d = True
pass
class childdummyclass(dummyclass):
def __init__(self, isman):
self.isman = isman
@classmethod
def can_speak(self): return True
@property
def man(self): return self.isman
if __name__ == "__main__":
object = new childdummyclass(True)
print object.can_speak()
print object.man()
print object.is_d
1. 警告: 类方法(classmethod)是类所拥有的方法, 传入的参数应该是cls, 而不是self;
2. 错误: Python没有new关键字, 如需修改new, 如单例模式, 可以重写(override)__new__;
3. 错误: @property, 表示属性, 不是方法, 则不需要加括号”()”, 直接调用object.man,即可;
4. 错误: 如果想使用基类的成员, 则需要初始化(__init__)基类, 如dummyclass.__init__(self),即可;
5. 额外: 类名尽量使用大写.
23、爬虫程序中有如下代理池,请随机选择一个代理。
PROXIES = [
{'ip_port': '111,11,221,32:80', 'user_pass': ''},
{'ip_port': '12.75.44.55:8120', 'user_pass': ''},
{'ip_port': '64.34.11.22:3330', 'user_pass': ''},
{'ip_port': '64.23.4.11:1025', 'user_pass': ''},
{'ip_port': '55.31.121.11:80', 'user_pass': ''},
]
import random
print(random.choice(PROXIES))
24、编写程序输入一个字符串,返回倒叙的结果,如:’abcdef’,返回’fedcba’
代码:
def selius():
ret = input('>>').strip()
return ret[::-1]
print(selius())
25、编程题
"""
一:定义一个学生类。有下面的类属性:
1 姓名
2 年龄
3 成绩(语文,数学,英语)[每课成绩的类型为整数]
类方法:
1 获取学生的姓名:get_name() 返回类型:str
2 获取学生的年龄:get_age() 返回类型:int
3 返回 3 门科目中最高的分数。get_course() 返回类型:int
写好类以后,可以定义 2 个同学测试下:
zm = Student('zhangming',20,[69,88,100])
返回结果:
zhangming
20
100
"""
代码
class Student:
def __init__(self, name, age, chengji):
self.name = name
self.age = age
self.chengji = chengji
def get_name(self):
print(self.name)
def get_age(self):
print(int(self.age))
def get_course(self):
print(max(self.chengji))
zm = Student('zhangming',20,[69,88,100])
zm.get_name()
zm.get_age()
zm.get_course()
26、描述多进程开发中 join 与 daemon。
join
当子线程调用join时,主线程会被阻塞,当子线程结束后,主线程才能继续执行。
当队列Queue调用join时,被Queue作用的函数会 挂起,等Queue中的数据被全部取出时,被挂起的函数才能继续执行。
daemon
守护进程:当子进程被设置为守护进程时,主进程结束,不管子进程是否执行完毕,都会随着主进程的结束而结束。
27、什么是异步,什么是异步阻塞?
所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。
如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发(通知),也就是领了一张小纸条,假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了这个等待的操作上面;
异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞。
28、写一个程序,包含十个线程,子线程必须等待主线程 sleep 10 秒钟之后才执行,并打印当前时间
主进程sleep10秒后再执行,代码:
from threading import Thread
import time
def func1():
print('当前时间', time.strftime('%Y-%m-%d %H:%M:%S'))
if __name__ == '__main__':
time.sleep(10)
for i in range(1,11):
t = Thread(target=func1)
t.start()
print('主线程')
29、请解释以下代码的输出结果。
z = [lambda x:x*i for i in range(3)]
x = [o(2) for o in z]
print x
执行结果为[4, 4, 4],z = [lambda x:x*i for i in range(3)],生成3个函数,函数的返回值为传入参数*i
x = [o(2) for o in z] 执行 z里面的每个函数得到3个返回值为4(实际上都是执行了x * 2),最后打印出[4,4,4]
30、写出程序,实现 socket 聊天并发实例,包含服务端、客户端
server端代码
import threading
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 9595))
s.listen(5)
def action(conn):
while True:
data = conn.recv(1024).decode('utf-8')
if data.upper() == 'Q':
break
print(data)
conn.send(data.upper().encode('utf-8'))
if __name__ == '__main__':
while True:
conn, addr = s.accept()
p = threading.Thread(target=action, args=(conn,))
p.start()
client端代码
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1', 9595))
while True:
msg = input('>>:').strip()
if not msg:continue
s.send(msg.encode('utf-8'))
if msg.upper() == 'Q':break
data = s.recv(1024).decode('utf-8')
print(data)
if data.upper() == 'Q':
s.send(data.encode('utf-8'))
break
s.close()
31、叙述进程、线程、协程的区别
进程与线程的区别:线程的开启,销毁,任务切换的时间开销小,在同一个进程中数据共享,能实现并发,不能脱离进程
进程负责管理分配资源,
协程遇到I/O阻塞就切换任务
32、
class Foo:
country = '中国'
print(country)
def __init__(self,name,country):
self.name = name
self.country = country
alex = Foo('sam','印度')
Foo.country = '泰国'
print(Foo.country)
print(alex.country)
说出打印顺序和内容,并解释原因
执行结果为中国,泰国,印度
代码从上往下运行 执行sam = Foo('sam','印度'),首先打印类的静态变量:中国,传两个参数,self.country = '印度'
执行 Foo.country = '泰国',改变类的静态变量country = '泰国',执行print(Foo.country),打印: 泰国
执行print(sam.country),之前已经传参,所以 self.country = '印度',打印print(sam.country),打印: 印度