Fork me on GitHub

Python练习题与答案

用Python语言写一个函数,输入一个字符串,返回倒序排列的结果:如:string_reverse(‘abcdefg’),返回’gfedcba’

1
2
3
4
5
def string_reverse(input_str):
return input_str[::-1]
print(string_reverse('nice'))

Python函数中经常有 args,*kwargs 这两个参数,它们是什么意思,为什么要使用它们?

在函数定义中使用args和kwargs传递可变长参数args用作传递非命名键值可变长参数列表(位置参数); kwargs用作传递键值可变长参数列表

当函数的参数不确定时,可以使用args 和**kwargs来 传递可变参数。 args储存可变的位置参数,它会接收任意多个参数并把这些参数作为元组传递给函数。**kwargs存储可变的关键字参数,允许你使用没有事先定义的参数名,将接收到任意多个关键字参数作为字典传递给函数。
注意函数的参数的顺序:args必须在kwargs前面,调用函数传递参数也必须依照此顺序

Python中的变量作用域(变量查找顺序)。

local 局部变量—>enclosed 闭包作用域 —-> Global 全局—->built-in变量

描述Python GIL的概念, 以及它对python多线程的影响?

GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行字节码。
线程释放GIL锁的情况:
在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL
Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100

Python使用多进程是可以利用多核的CPU资源的。

is和==的区别是?

Python中的对象包含三要素:id、type、value
其中id用来唯一标识一个对象,type标识对象的类型,value是对象的值
is判断的是a对象是否就是b对象,是通过id来判断的
==判断的是a对象的值是否和b对象的值相等,是通过value来判断的

只有数值型和字符串型的情况下,a is b才为True,当a和b是tuple,list,dict或set型时,a is b为False。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = 1
b = 1
a is b # True
a == b # True
a = 'abc'
b = 'abc'
a is b # True
a == b # True
a = (1, 2, 3)
b = (1, 2, 3)
a == b # True
a is b # False

能简单说一下你了解的socket吗?

我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯
中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大
,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可
以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。

能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,什么是socket呢?我们经常把
socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽
象为几个简单的接口供应用层调用已实现进程在网络中通信。

如何用列表生成式生成[1,4,9,16,25,36,49,64,81,100]?

1
[x*x for x in range(1,11)]

生成器是什么?有什么作用?请写出一个生成器

1
a = ( i for i in range(11))

边循环边计算,保存的是算法,每次调用会执行一次算法。

Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是
立即产生结果。这也是生成器的主要好处。

生成器的唯一注意事项就是:生成器只能遍历一次

Python有两种不同的方式提供生成器:

生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返
回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个
结果列表

def gensquares(N):
for i in range(N):
yield i ** 2

for item in gensquares(5):
print(item)

关于 python 程序的运行性能方面,有什么手段能提升性能?

io密集型用多线程
计算密集型用进程
1、使用多进程,充分利用机器的多核性能
2、对于性能影响较大的部分代码,可以使用C或C++编写
3、对于IO阻塞造成的性能影响,可以使用IO多路复用来解决
4、尽量使用python的内建函数
5、尽量使用局部变量

(str.split()字符串的切割)

将字符串:”k:1|k1:2|k2:3|k3:4”,处理成 python 字典:{k:1, k1:2, … }

1
2
3
4
5
6
7
str1 = "k:1|k1:2|k2:3|k3:4"
def str2dict(str1):
dict1 = {}
for iterms in str1.split('|'):
key,value = iterms.split(':')
dict1[key] = value
return dict1

1 or 2 和 1 and 2 分别输出什么?

or 和 and 都是从做往右看

or 只要左边不为0就返回左边的值,他就不会去看右边的值。如果左边为0,他会去看右边的值右边
值为0就返回0,右边不为0就返回右边的值。

and 只要左边为0就不看右边了,直接返回0。如果左边不为0,右边为0就返回0。如果左边不为0,
他会去看右边,右边不为0就返回右边的值。

看代码

1
2
3
4
5
6
value = "B" and "A" or "C"
print(value)
也是从左向右看
# A
# 整个式子 不断去向右查看,直到能确定为真就停下来

看代码写结果

1
2
3
4
5
6
7
v1 = [i % 2 for i in range(10)]
v2 = (i % 2 for i in range(10))
print(v1,v2)
v1 = [0,1,0,1,0,1,0,1,0,1] 为列表生成式
v2 = 为<generator object <genexpr> at 0x00E4F990>为生成式

输出以下结果

1
2
for i in range(5,0,1):
print(i)

请将 “1,2,3”,变成 [“1”,”2”,”3”]。将[‘q’, ‘w’, ‘e’, ‘r’]变成 ‘q,w,e,r’

1
2
"1,2,3".split(',')
','.join(['q', 'w', 'e', 'r'])

一行生成 9 * 9乘法表,列表生成式(python装B必备)

1
print('\n'.join([ ' '.join( [ '{}*{} = {}'.format(x,y,x*y) for y in range(1,x+1)] ) for x in range(1,10)]))

创建一个简单tcp服务器需要的流程?

1.socket创建一个套接字
2.bind绑定ip和port
3.listen使套接字变为可以被动链接
4.accept等待客户端的链接
5.recv/send接收发送数据

谈谈对线程、进程、协程的理解

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配
和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。
由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈寄存器、虚拟内存、
文件句柄等)比较大,但相对比较稳定安全。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.
线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和
栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内
存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和
栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存
器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。