首页 > 编程语言 > 详细

史上最全python面试题详解(附带详细答案(关注、持续更新))

时间:2020-01-01 21:23:46      阅读:103      评论:0      收藏:0      [点我收藏+]

python基础题(53道题详解)

1、简述解释型和编译型编程语言?

概念:

  • 编译型语言:把做好的源程序全部编译成二进制代码的可运行程序。然后,可直接运行这个程序。
  • 解释型语言:把做好的源程序翻译一句,然后执行一句,直至结束!

区别:

  • 编译型语言,执行速度快、效率高;依赖编译器、跨平台性差些。如C、C++、Delphi、Pascal,Fortran。
  • 解释型语言,执行速度慢、效率低;依赖解释器、跨平台性好。如Java、Basic.

2、Python解释器种类以及特点

  • CPython
    • c语言开发的 使用最广的解释器
  • IPython
    • 基于cpython之上的一个交互式计时器 交互方式增强 功能和cpython一样
  • PyPy
    • 目标是执行效率 采用JIT技术 对python代码进行动态编译,提高执行效率
  • JPython
    • 运行在Java上的解释器 直接把python代码编译成Java字节码执行
  • IronPython
    • 运行在微软 .NET 平台上的解释器,把python编译成. NET 的字节码

3、python常见的PEP8规范

  • 每级缩进用4个空格
  • Python 3中不允许混合使用Tab和空格缩进。
  • 限制所有行的最大行宽为79字符。
  • 在核心Python发布的代码应该总是使用UTF-8(ASCII在Python 2)。
  • 推荐绝对路径导入,因为它们通常更可读

 4、通过代码实现如下进制转换:

技术分享图片
1 hex()
2 转换一个整数对象为十六进制的字符串
3 
4 >>> hex(16)
5 0x10
6 >>> hex(18)
7 0x12
8 >>> hex(32)
9 0x20
技术分享图片
技术分享图片
1 oct()
2 转换一个整数对象为八进制的字符串
3 
4 >>> oct(8)
5 0o10
6 >>> oct(166)
7 0o246
技术分享图片
技术分享图片
1 bin()
2 转换一个整数对象为二进制字符串
3 
4 >>> bin(10)
5 0b1010
6 >>> bin(255)
7 0b11111111
技术分享图片
技术分享图片
 1 chr()
 2 转换一个[0, 255]之间的整数为对应的ASCII字符
 3 
 4 >>> chr(65)
 5 A
 6 >>> chr(67)
 7 C
 8 >>> chr(90)
 9 Z
10 >>> chr(97)
11 a
技术分享图片
技术分享图片
1 ord()
2 将一个ASCII字符转换为对应整数
3 
4 >>> ord(A)
5 65
6 >>> ord(z)
7 122
技术分享图片
技术分享图片
 1 16进制转10进制
 2 >>> int(10, 16)
 3 16
 4 >>> int(0x10, 16)
 5 16
 6 
 7 8进制转10进制
 8 >>> int(0o10, 8)
 9 8
10 >>> int(10, 8)
11 8
12 
13 2进制转10进制
14 >>> int(0b1010, 2)
15 10
16 >>> int(1010, 2)
17 10
技术分享图片

5、python递归的最大层数

技术分享图片
 1 import sys
 2 sys.setrecursionlimit(100000)
 3 
 4 def foo(n):
 5     print(n)
 6     n += 1
 7     foo(n)
 8         
 9 if __name__ == __main__:
10     foo(1)
技术分享图片

得到的最大数字在3925-3929之间浮动,这个是和计算机有关系的,不然也不会是一个浮动的数字了(数学逻辑讲求严谨)

6、三元运算规则以及应用场景

  •         三元运算符就是在赋值变量的时候,可以直接加判断,然后赋值
  •         三元运算符的功能与‘if....else‘流程语句一致,它在一行中书写,代码非常精炼,执行效率更高
  •         格式:[on_true] if [expression] else [on_false]
  •         res = 值1 if 条件 else 值2

7、列举 Python2和Python3的区别

  • print  
  • input
  • 技术分享图片
     1 问题:如何获取编码方式的信息?
     2 获取目标bytes的编码方式
     3 这一情况可以通过chardet模块的detect()函数来获取信息,chardet是第三方库,可以通过pip来安装
     4 
     5 b是待检测的bytes变量
     6 
     7 import chardet
     8 print(chardet.detect(b))
     9 ######output####
    10  {confidence: 1.0, encoding: ascii}
    11 1
    12 2
    13 3
    14 4
    15 5
    16 confidence是指匹配程度,encoding是指可能的编码方式
    17 
    18 获取当前环境的编码方式 
    19 这一情况可以使用sys模块下的getdefaultencoding()函数来获取信息
    20 
    21 import sys
    22 print(sys.getdefaultencoding())
    23 
    24 ######## output#####
    25 utf-8
    技术分享图片
  • 问题在控制台上看到的到底是什么
技术分享图片
 1 写上面的东西的时候产生了一个疑问,现在已经知道Python内部存储str的方式是使用unicode字符集,但是我们在屏幕上看到的并不是unicode字符集
 3 s = "你好"
 4 print(s)
 6 #########output#############
 7 你好
13 s的 unicode 是 \u4f60\u597d
14 1
15 那么,这中间应该是进行了某种转换 
16 实际上,在执行print(str)的时候,python内部执行了encoding操作,控制台拿到的其实是一个bytes变量 
17 之后,控制台又根据环境内部的编码方式,将所得到的bytes内容进行decoding的操作,就显示了原先str的内容
技术分享图片
  • 打开文件不再支持 file 方法,只能用 open 
  • range不再返回列表,而是一个可迭代的range对象
  • 除法 / 不再是整除,而是得到浮点数,整除需要用双斜杠 //
  • urllib和urllib2合并成了urllib,常用的urllib2.urlopen()变成了urllib.request.urlopen()
  • 字符串及编码相关有大变动,简单来说就是原来的str变成了新的bytes,原来的unicode变成了新的str。

8、xrange和range的区别

  python2中 xrange 用法与 range 完全相同,所不同的是生成的不是一个list对象,而是一个生成器。

9、python的read() 、readline()、readlines()、xreadlines()

  • read()会读取整个文件,将读取到底的文件内容放到一个字符串变量,返回str类型。
  • readline()读取一行内容,放到一个字符串变量,返回str类型。
  • readlines() 读取文件所有内容,按行为单位放到一个列表中,返回list类型。
  • xreadlines()返回一个生成器,来循环操作文件的每一行。

10、列举布尔值为False的常见值

  None、""、0、[]、()、{}

11、字符串、列表、元组、字典每个常用的5个方法(整型,浮点,字符串,布尔型,列表、元组、字典、集合、日期)

字符串:

技术分享图片
# encoding:utf-8
__author__ = Fioman
__date__ = 2018/11/19 15:10

# 1. 去掉空格和特殊符号
name = " abcdefgeyameng  "
name1 = name.strip()  # 并不会在原来的字符串上操作,返回一个去除了两边空白的字符串
print(name1, len(name1), name, len(name))
# abcdefgeyameng 14  abcdefgeyameng   17

# 去掉左边的空格和换行符
name2 = name.lstrip()
print(name2, len(name2))# print(name2, len(name2))#

# 去掉右边的空格和换行符
name3 = name.rstrip()
print(name3, len(name3)) # abcdefgeyameng 15


# 2.字符串的搜索和替换
name.count(e)  # 查找某个字符在字符串中出现的次数
name.capitalize() # 首字母大写
name.center(100,-) # 把字符串方中间,两边用-补齐,100表示占位多少
name.find(a) # 找到这个字符返回下标,多个时返回第一个,不存在时返回-1
name.index(a) # 找到这个字符返回下标,多个时返回第一个,不存在时报错
print(name.replace(name,123)) # 字符串的替换
name.replace(abc,123) # 注意字符串的替换的话,不是在原来的字符串上进行替换.而是返回一个替换后的字符串.

# 3.字符串的测试和替换函数
name.startswith("abc") # 是否以abc开头
name.endswith("def") # 是否以def结尾
name.isalnum() # 是否全是字母和数字,并且至少包含一个字符
name.isalpha() # 是否全是字母,并至少包含一个字符
name.isdigit() # 是否全是数字,并且至少包含一个字符
name.isspace() # 是否全是空白字符,并且至少包含一个字符
name.islower() # 是否全是小写
name.isupper() # 是否全是大写
name.istitle() # 是否是首字母大写

# 4.字符串的分割
name.split(‘‘) # 默认按照空格进行分隔,从前往后分隔
name.rsplit() # 从后往前进行分隔

# 5.连接字符串
..join(name) # 用.号将一个可迭代的序列拼接起来

name = geyameng
# 6.截取字符串(切片)
name1 = name[0:3] # 第一位到第三位的字符,和range一样不包含结尾索引
name2 = name[:] # 截取全部的字符
name3 = name[6:] # 截取第6个字符到结尾
name4 = name[:-3] # 截取从开头到最后一个字符之前
name5 = name[-1] # 截取最后一个字符
name6 = name[::-1] # 创造一个与原字符串顺序相反的字符串
name7 = name[:-5:-1] # 逆序截取
技术分享图片

列表:

技术分享图片
# encoding:utf-8
__author__ = Fioman
__date__ = 2018/11/19 16:26

# 1.创建一个列表
list1 = [1, 2, 3, 4]
list2 = list("1234")
print(list1, list2)
print(list1 == list2)
# 以上创建的两个列表是等价的,都是[‘1‘, ‘2‘, ‘3‘, ‘4‘]

# 2.添加新元素
# 末尾追加
a = [1, 2, 3, 4, 5]
a.append(6)
print(a)

# 指定位置的前面插入一个元素
a.insert(2, 100)  # 在下标为2的前面插入一个元素100
print(a)

# 扩展列表list.extend(iterable),在一个列表上追加一个列表
a.extend([10, 11, 12])
print(a)

# 3.遍历列表
# 直接遍历
for i in a:
    print(i)

# 带索引的遍历列表
for index, i in enumerate(a):
    print(i, index)

# 4.访问列表中的值,直接通过下标取值.list[index]
print(a[2])

# 从list删除元素
# List.remove() 删除方式1:参数object 如果重复元素,只会删除最靠前的.
a = [1,2,3]
a.remove(2) # 返回值是None

# List.pop()  删除方式2:pop 可选参数index,删除指定位置的元素 默认为最后一个元素
a = [1,2,3,4,5]
a.pop()
print(a)

a.pop(2)
print(a)

# 终极删除,可以删除列表或指定元素或者列表切片,list删除后无法访问
a = [1,2,3,4,5,6]
del  a[1]
print(a) # 1, 3, 4, 5, 6]

del a[1:]
print(a) # 1

del a
# print(a) # 出错,name a is not defined


# 排序和反转代码
# reverse 反转列表
a = [1,2,3,4,5]
a.reverse()
print(a)

# sort 对列表进行排序,默认升序排列.有三个默认参数cmp = None,key = None,reverse = False

# 7.Python的列表的截取与字符串操作类型相同,如下所示
L = [spam,Spam,SPAM!]
print(L[-1]) # [‘SPAM‘]

# 8.Python列表操作的函数和方法
len(a)  # 列表元素的个数
max(a)  # 返回列表元素最大值
min(a)  # 返回列表元素最小值
list(tuple) #将一个可迭代对象转换为列表

# 列表常用方法总结
a.append(4)
a.count(1)
a.extend([4,5,6])
a.index(3)
a.insert(0,2)
a.remove()
a.pop()
a.reverse()
a.sort()
技术分享图片

元组:

1.用一个可迭代对象生成元组
    T = tuple(abc)
技术分享图片
对元组进行排序
注意
当对元组进行排序的时候,通常先得将它转换为列表并使得它成为一个可变对象.或者使用sorted方法,它接收任何序列对象.

T = (c,a,d,b)
tmp = list(T)
tmp.sort()  ==> [a,b,c,d]
T = tunple(tmp)
sorted(T)
技术分享图片

字典:

技术分享图片
以下实例展示了 fromkeys()函数的使用方法:

实例(Python 2.0+)
#!/usr/bin/python
# -*- coding: UTF-8 -*-
seq = (Google, Runoob, Taobao)
dict = dict.fromkeys(seq)
print "新字典为 : %s" % str(dict)
dict = dict.fromkeys(seq, 10)
print "新字典为 : %s" % str(dict)
以上实例输出结果为:

新字典为 : {Google: None, Taobao: None, Runoob: None}
新字典为 : {Google: 10, Taobao: 10, Runoob: 10}
技术分享图片
通过zip函数构建字典
D = dict(zip(keyslist,valueslist))
通过赋值表达式元组构造字典(键必须是字符串,因为如果不是字符串,构造的时候也会当成是字符串处理)
D = dict(name=Bob,age=42)  ==> {name:Bob,age:42}
列出所有的键,值.注意得到的是一个可迭代对象,而不是列表.用的时候需要转换
D.keys()    
D.values()  
D.items()  --> 键 + 值
删除字典(根据键)以及长度
D.pop(key)    
len(D) 
del D[key]
新增或者是修改键对应的值
D[key] = value  # 如果key已经存在则修改,如果不存在就创建.
字典推导式
D = [x:x**2 for x in range(10) if x %2 == 0]

 12、lambda表达式格式以及应用场景

1、lambda函数与list的结合使用

技术分享图片
list = lambda:x for x in range(10)
print (list[0])
>>>9

list = lambda x:x for x in range(10)
print (list[0])
>>>0
技术分享图片

2、map,filter,reduce函数

技术分享图片
例子:
a = [(a,1),(b,2),(c,3),(d,4)]
a_1 = list(map(lambda x:x[0],a))
如上例子,map函数第一个参数是一个lambda表达式,输入一个对象,返回该对象的第一个元素。第二个就是需要作用的对象,此处是一个列表。Python3中map返回一个map对象,我们需要人工转为list,得到的结果就是[‘a’,’b’,’c’,’d’] 
例子:
a = [1,2,3,4]
b = [2,3,4,5]
a_1 = list(map(lambda x,y:x+y,a,b))
上边这个例子是为了说明,lambda表达式参数可以是多个。返回结果是[3,5,7,9]
技术分享图片
技术分享图片
例子:
a = [1,2,3,4,5,6,7]
a_1 = filter(lambda x:x<4,a)
如上例子,定义lambda表达式,筛选a列表中小于4的元素,结果为[1,2,3]。filter函数直接返回一个列表,无需再进行转换,第三个是初始值,我们没给初始值,那么开始操作的两个元素就是序列的前两个。否则将使用我们给出的初始值和序列第一个元素操作,然后结果再与第三个元素操作,以此类推。上个例子结果是28
技术分享图片
技术分享图片
例子:
from functools import reduce #python3需要导入此模块
a = [1,2,3,4,5,6,7]
a_1 = reduce(lambda x,y:x+y,a)
reduce中使用的lambda表达式需要两个参数,reduce函数共三个参数,
第一个是就是lambda表达式,第二个是要累计的序列,第三个是初始值,
我们没给初始值,那么开始操作的两个元素就是序列的前两个。否则将使
用我们给出的初始值和序列第一个元素操作,然后结果再与第三个元素操
作,以此类推。上个例子结果是28
技术分享图片

3、字典多条件排序

技术分享图片
例子:
dict = {a:1,b:2,c:3,d:4,e:3,f:1,g:7}
sorted_dict_asc = sorted(dict.items(),key=lambda item:item[0])
sorted_dict_dsc = sorted(dict.items(),key=lambda item:item[0],reverse=True)

输出(第一个升序,第二个降序):
[(a, 1), (b, 2), (c, 3), (d, 4), (e, 3), (f, 1), (g, 7)]
[(g, 7), (f, 1), (e, 3), (d, 4), (c, 3), (b, 2), (a, 1)]]
技术分享图片

13、pass的作用

  pass是空语句占位符,是为了保持程序结构的完整性。

14、*arg和**kwarg作用

技术分享图片
定义函数时,使用*arg和**kwarg
*arg和**kwarg 可以帮助我们处理上面这种情况,允许我们在调用函数的时候传入多个实参
def exmaple2(required_arg, *arg, **kwarg):
    if arg:
        print "arg: ", arg

    if kwarg:
        print "kwarg: ", kwarg

exmaple2("Hi", 1, 2, 3, keyword1 = "bar", keyword2 = "foo")
>> arg:  (1, 2, 3)
>> kwarg:  {keyword2: foo, keyword1: bar}
从上面的例子可以看到,当我传入了更多实参的时候
*arg会把多出来的位置参数转化为tuple
**kwarg会把关键字参数转化为dict
技术分享图片

15、is和==的区别

  • Python中对象包含的三个基本要素,分别是:id(身份标识)、type(数据类型)和value(值)。
  • ==是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等
  • is也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同。

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

16、简述Python的深浅拷贝以及应用场景

深浅拷贝用法来自copy模块。

导入模块:import copy

浅拷贝:copy.copy

深拷贝:copy.deepcopy

  对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。

  字面理解:浅拷贝指仅仅拷贝数据集合的第一层数据,深拷贝指拷贝数据集合的所有层。所以对于只有一层的数据集合来说深浅拷贝的意义是一样的,比如字符串,数字,还有仅仅一层的字典、列表、元祖等.

  字典(列表)的深浅拷贝

    赋值:

import copy
n1 = {‘k1‘:‘wu‘,‘k2‘:123,‘k3‘:[‘alex‘,678]}
n2 = n1

技术分享图片

 

浅拷贝:

import copy
n1 = {‘k1‘:‘wu‘,‘k2‘:123,‘k3‘:[‘alex‘,678]}
n3 = copy.copy(n1)

技术分享图片

 

深拷贝:

import copy
n1 = {‘k1‘:‘wu‘,‘k2‘:123,‘k3‘:[‘alex‘,678]}
n4 = copy.deepcopy(n1)

技术分享图片

  深拷贝的时候python将字典的所有数据在内存中新建了一份,所以如果你修改新的模版的时候老模版不会变。相反,在浅copy 的时候,python仅仅将最外层的内容在内存中新建了一份出来,字典第二层的列表并没有在内存中新建,所以你修改了新模版,默认模版也被修改了。

17、Python是如何进行内存管理的

 

:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制

 

一、对象的引用计数机制

 

Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。

 

引用计数增加的情况:

 

1,一个对象分配一个新名称

 

2,将其放入一个容器中(如列表、元组或字典)

 

引用计数减少的情况:

 

1,使用del语句对对象别名显示的销毁

 

2,引用超出作用域或被重新赋值

 

Sys.getrefcount( )函数可以获得对象的当前引用计数

 

多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。

 

二、垃圾回收

 

1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。

 

2,当两个对象ab相互引用时,del语句可以减少ab的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。

 

三、内存池机制

 

Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。

 

1Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。

 

2Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc

 

3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

 

18、Python的可变类型和不可变类型

  • 数字、字符串、元组是不可变的,列表、字典是可变的。

对象池:

小整数对象池
[-5, 256] 这些小整数被定义在了一个整数对象池里,当引用小整数时会自动引用整数对象池里的对象,所以这些小整数不会重复创建,当多个变量指向同一个小整数时,实质上它们指向的是同一个对象。

字符串对象池
字符串对象是不可变对象,python有个intern机制,简单说就是维护一个字典,这个字典维护已经创建字符串(key)和它的字符串对象的地址(value),每次创建字符串对象都会和这个字典比较,没有就创建,重复了就用指针进行引用就可以了。intern机制处理字符串长度小于等于20且仅由数字字母下划线构成的,只创建一次。

19、列举常见的内置函数

数学相关

  • abs(a) : 求取绝对值。abs(-1)
  • max(list) : 求取list最大值。max([1,2,3])
  • min(list) : 求取list最小值。min([1,2,3])
  • sum(list) : 求取list元素的和。 sum([1,2,3]) >>> 6
  • sorted(list) : 排序,返回排序后的list。
  • len(list) : list长度,len([1,2,3])
  • divmod(a,b): 获取商和余数。 divmod(5,2) >>> (2,1)
  • pow(a,b) : 获取乘方数。pow(2,3) >>> 8
  • round(a,b) : 获取指定位数的小数。a代表浮点数,b代表要保留的位数。round(3.1415926,2) >>> 3.14
  • range(a[,b]) : 生成一个a到b的数组,左闭右开。 range(1,10) >>> [1,2,3,4,5,6,7,8,9]

类型转换

  • int(str) : 转换为int型。int(‘1‘) >>> 1
  • float(int/str) : 将int型或字符型转换为浮点型。float(‘1‘) >>> 1.0
  • str(int) : 转换为字符型。str(1) >>> ‘1‘
  • bool(int) : 转换为布尔类型。 str(0) >>> False str(None) >>> False
  • bytes(str,code) : 接收一个字符串,与所要编码的格式,返回一个字节流类型。bytes(‘abc‘, ‘utf-8‘) >>> b‘abc‘ bytes(u‘爬虫‘, ‘utf-8‘) >>> b‘\xe7\x88\xac\xe8\x99\xab‘
  • list(iterable) : 转换为list。 list((1,2,3)) >>> [1,2,3]
  • iter(iterable): 返回一个可迭代的对象。 iter([1,2,3]) >>> <list_iterator object at 0x0000000003813B00>
  • dict(iterable) : 转换为dict。 dict([(‘a‘, 1), (‘b‘, 2), (‘c‘, 3)]) >>> {‘a‘:1, ‘b‘:2, ‘c‘:3}
  • enumerate(iterable) : 返回一个枚举对象。
  • tuple(iterable) : 转换为tuple。 tuple([1,2,3]) >>>(1,2,3)
  • set(iterable) : 转换为set。 set([1,4,2,4,3,5]) >>> {1,2,3,4,5} set({1:‘a‘,2:‘b‘,3:‘c‘}) >>> {1,2,3}
  • hex(int) : 转换为16进制。hex(1024) >>> ‘0x400‘
  • oct(int) : 转换为8进制。 oct(1024) >>> ‘0o2000‘
  • bin(int) : 转换为2进制。 bin(1024) >>> ‘0b10000000000‘
  • chr(int) : 转换数字为相应ASCI码字符。 chr(65) >>> ‘A‘
  • ord(str) : 转换ASCI字符为相应的数字。 ord(‘A‘) >>> 65

相关操作

  • eval() : 执行一个表达式,或字符串作为运算。 eval(‘1+1‘) >>> 2
  • exec() : 执行python语句。 exec(‘print("Python")‘) >>> Python
  • filter(func, iterable) : 通过判断函数fun,筛选符合条件的元素。 filter(lambda x: x>3, [1,2,3,4,5,6]) >>> <filter object at 0x0000000003813828>
  • map(func, *iterable) : 将func用于每个iterable对象。 map(lambda a,b: a+b, [1,2,3,4], [5,6,7]) >>> [6,8,10]
  • zip(*iterable) : 将iterable分组合并。返回一个zip对象。 list(zip([1,2,3],[4,5,6])) >>> [(1, 4), (2, 5), (3, 6)]
  • type():返回一个对象的类型。
  • id(): 返回一个对象的唯一标识值。
  • hash(object):返回一个对象的hash值,具有相同值的object具有相同的hash值。 hash(‘python‘) >>> 7070808359261009780
  • help():调用系统内置的帮助系统。
  • isinstance():判断一个对象是否为该类的一个实例。
  • issubclass():判断一个类是否为另一个类的子类。
  • globals() : 返回当前全局变量的字典。
  • next(iterator[, default]) : 接收一个迭代器,返回迭代器中的数值,如果设置了default,则当迭代器中的元素遍历后,输出default内容。
  • reversed(sequence) : 生成一个反转序列的迭代器。 reversed(‘abc‘) >>> [‘c‘,‘b‘,‘a‘]

20、Python写9*9乘法表的两种简单方法

1 for i in range(1,10):
2     for j in range(1,i+1):
3         print("%s * %s = %s" %(j,i,i*j),end="")
4     print("")
print "\n".join("\t".join(["%s*%s=%s" %(x,y,x*y) for y in range(1, x+1)]) for x in range(1, 10))

21、如何安装第三方模块?以及用过哪些第三方模块?

  pip install 模块名

一、Python爬虫

1. 请求

requests(第三方模块)

2. 解析:

bs4(即beautifulsoup,第三方模块)

3. 储存:

pymongo(第三方模块):

  把数据写入MongoDB

MySQL-python(第三方模块):

  把数据写入MySQL里面。

协程:gevent(第三方模块)

二、Python数据分析&科学计算

numpy(第三方模块,C拓展):

  Copy了MATLAB的数据结构。很多数据分析和科学计算库的底层模块。提供了良好的数组数据结构和C拓展接口。

pandas(第三方模块,C拓展):

  Copy了R的data frame的数据结构。

22、常用模块都有那些?

技术分享图片
 1 import time
 2 import datetime
 3 
 4 print(time.asctime())      # 返回时间格式:Sun May  7 21:46:15 2017
 5 print(time.time())         # 返回时间戳 ‘1494164954.6677325’
 6 print(time.gmtime())       # 返回本地时间 的struct time对象格式,time.struct_time(tm_year=2017, tm_mon=5, tm_mday=7, tm_hour=22, tm_min=4, tm_sec=53, tm_wday=6, tm_yday=127, tm_isdst=0)
 7 print(time.localtime())    # 返回本地时间 的struct time对象格式,time.struct_time(tm_year=2017, tm_mon=5, tm_mday=7, tm_hour=22, tm_min=4, tm_sec=53, tm_wday=6, tm_yday=127, tm_isdst=0)
 8 print(time.gmtime(time.time()-800000))   # 返回utc时间的struc时间对象格式
 9 print(time.asctime(time.localtime()))    # 返回时间格式Sun May  7 22:15:09 2017
10 print(time.ctime())                      # 返回时间格式Sun May  7 22:15:09 2017
11 print(time.strftime(%Y-%m-%d))         #默认当前时间 2017-05-07
12 print(time.strftime(%Y-%m-%d,time.localtime())) #默认当前时间 2017-05-07
13 
14 string_struct = time.strptime("2016/05/22","%Y/%m/%d") # 将日期字符串 转成 struct时间对象格式
15 print(string_struct)                     # 返回struct time对象格式 time.struct_time(tm_year=2016, tm_mon=5, tm_mday=22, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=143, tm_isdst=-1)
16 
17 # 将日期字符串转成时间戳
18 struct_stamp = time.mktime(string_struct) # 将struct time时间对象转成时间戳
19 print(struct_stamp)                         # 返回时间戳 ‘1463846400.0’
20 
21 # 将时间戳转为字符串格式
22 print(time.gmtime(time.time()-86640))         # 将utc时间戳转换成struct_time格式
23 print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) # 将utc struct_time格式转成指定的字符串格式
24 
25 
26 # 时间加减
27 print(datetime.datetime.now())           # 返回当前时间 2017-05-07 22:36:45.179732
28 print(datetime.date.fromtimestamp(time.time()))  # 时间戳直接转换成日期格式 2017-05-07
29 print(datetime.datetime.now() + datetime.timedelta(3))    # 返回时间在当前日期上 +3 天
30 print(datetime.datetime.now() + datetime.timedelta(-3))    # 返回时间在当前日期上 -3 天
31 print(datetime.datetime.now() + datetime.timedelta(hours= 3)) # 返回时间在当前时间上 +3 小时
32 print(datetime.datetime.now() + datetime.timedelta(minutes= 30)) # 返回时间在当前时间上 +30 分钟
33 
34 c_time  = datetime.datetime.now()
35 print(c_time)                          # 当前时间为 2017-05-07 22:52:44.016732
36 print(c_time.replace(minute=3,hour=2)) # 时间替换 替换时间为‘2017-05-07 02:03:18.181732’
37 
38 print(datetime.timedelta)      # 表示时间间隔,即两个时间点之间的长度
39 print (datetime.datetime.now() - datetime.timedelta(days=5))  # 返回时间在当前时间上 -5 天
40 
41 # python 日历模块
42 import calendar
43 
44 print(calendar.calendar(theyear= 2017))     # 返回2017年整年日历
45 print(calendar.month(2017,5))               # 返回某年某月的日历,返回类型为字符串类型
46 
47 calendar.setfirstweekday(calendar.WEDNESDAY) # 设置日历的第一天(第一天以星期三开始)
48 cal = calendar.month(2017, 4)
49 print (cal)
50 
51 print(calendar.monthrange(2017,5))        # 返回某个月的第一天和这个月的所有天数
52 print(calendar.monthcalendar(2017,5))     # 返回某个月以每一周为元素的序列
53 
54 cal = calendar.HTMLCalendar(calendar.MONDAY)
55 print(cal.formatmonth(2017, 5))           # 在html中打印某年某月的日历
56 
57 print(calendar.isleap(2017))             # 判断是否为闰年
58 print(calendar.leapdays(2000,2017))       # 判断两个年份间闰年的个数
技术分享图片
技术分享图片
 1 import random
 2 
 3 # 随机数
 4 print(random.random())              # 返回一个随机小数‘0.4800545746046827‘
 5 print(random.randint(1,5))          # 返回(1-5)随机整型数据
 6 print(random.randrange(1,10))       # 返回(1-10)随机数据
 7 
 8 # 生成随机验证码
 9 code = ‘‘
10 for i in range(4):
11     current = random.randrange(0,4)
12     if current != i:
13         temp = chr(random.randint(65,90))
14     else:
15         temp = random.randint(0,9)
16     code += str(temp)
17 
18 print(code)
技术分享图片
技术分享图片
import os

print(os.getcwd())        # 获得当前工作目录
print(os.chdir("dirname")) # 改变当前脚本的工作路径,相当于shell下的cd
print(os.curdir)            # 返回当前目录‘.‘
print(os.pardir)            # 获取当前目录的父目录字符串名‘..‘
print(os.makedirs(dirname1/dirname2))     # 可生成多层递归目录
print(os.removedirs(dirname1/dirname2))      # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
print(os.mkdir(test4))         # 生成单级目录;相当于shell中mkdir dirname
print(os.rmdir(test4))        # 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
print(os.listdir(/pythonStudy/s12/test))   # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
print(os.remove(log.log))            # 删除一个指定的文件
print(os.rename("oldname","newname"))    # 重命名文件/目录)
print(os.stat(/pythonStudy/s12/test))     # 获取文件/目录信息
print(os.pathsep)            # 输出用于分割文件路径的字符串‘;‘
print(os.name)               # 输出字符串指示当前使用平台。win->‘nt‘; Linux->‘posix‘
print(os.system(command=bash))   # 运行shell命令,直接显示
print(os.environ)                  # 获得系统的环境变量
print(os.path.abspath(/pythonStudy/s12/test))   # 返回path规范化的绝对路径
print(os.path.split(/pythonStudy/s12/test))     # 将path分割成目录和文件名二元组返回
print(os.path.dirname(/pythonStudy/s12/test))    # 返回path的目录。其实就是os.path.split(path)的第一个元素
print(os.path.basename(/pythonStudy/s12/test))   # 返回path最后的文件名。如果path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
print(os.path.exists(test))                 # 判断path是否存在
print(os.path.isabs(/pythonStudy/s12/test))    # 如果path是绝对路径,返回True
print(os.path.isfile(test))                   # 如果path是一个存在的文件,返回True。否则返回False
print(os.path.isdir(/pythonStudy/s12/test))    # 如果path是一个存在的目录,则返回True。否则返回False
print(os.path.getatime(/pythonStudy/s12/test))   # 返回path所指向的文件或者目录的最后存取时间
print(os.path.getmtime(/pythonStudy/s12/test))   # 返回path所指向的文件或者目录的最后修改时间
技术分享图片
技术分享图片
import sys

print(sys.argv)          # 命令行参数List,第一个元素是程序本身路径
print(sys.exit(n))     # 退出程序,正常退出时exit(0)
print(sys.version)       # 获取python的版本信息
print(sys.path)          # 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
print(sys.platform)      # 返回操作平台的名称
技术分享图片
技术分享图片
# xml的格式如下,就是通过<>节点来区别数据结构的:
import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)

#遍历xml文档
for child in root:
    print(child.tag, child.attrib)
    for i in child:
        print(i.tag,i.text)

#只遍历year 节点
for node in root.iter(year):
    print(node.tag,node.text)

# 修改和删除xml文档内容
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()

#修改
for node in root.iter(year):
    new_year = int(node.text) + 1
    node.text = str(new_year)
    node.set("updated","yes")
tree.write("xmltest.xml")

#删除node
for country in root.findall(country):
   rank = int(country.find(rank).text)
   if rank > 50:
       root.remove(country)
tree.write(output.xml)

# 自己创建xml文档
import xml.etree.ElementTree as ET

new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
age = ET.SubElement(name, "age", attrib={"checked": "no"})
age = ET.SubElement(name, "age")
age.text = 33
name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
age = ET.SubElement(name2, "age")
age.text = 19
et = ET.ElementTree(new_xml)  # 生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True)
ET.dump(new_xml)  # 打印生成的格式
技术分享图片

 

python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug()info()warning()error() and critical() 5个级别。

技术分享图片
import logging

# %(message)s 日志信息
# %(levelno)s 日志级别
# datefmt  设置时间格式
# filename  设置日志保存的路径
# level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,
# 在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。
logging.basicConfig(format=%(asctime)s %(message)s %(levelno)s, datefmt=%m/%d/%Y %I:%M:%S %p,filename=example.log,level=logging.INFO)
logging.debug(This message should go to the log file)
logging.info(So should this)
技术分享图片

 

23、re的match和search区别?

re.match()从开头开始匹配string。 
re.search()从anywhere 来匹配string。

# 多行模式
>>> re.match(X, A\nB\nX, re.MULTILINE) # No match >>> re.search(^X, A\nB\nX, re.MULTILINE) # Match <_sre.SRE_Match object at ...>

24、什么是正则的贪婪匹配

1 如:String str="abcaxc";
2   Patter p="ab.*c";
3   贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如上面使用模式p匹配字符串str,结果就是匹配到:abcaxc(ab.*c)。
4   非贪婪匹配:就是匹配到结果就好,就少的匹配字符。如上面使用模式p匹配字符串str,结果就是匹配到:abc(ab.*c)。

25、def func(a,b=[]) 这种写法有什么坑?

技术分享图片
def func(a,b=[]):
    b.append(a)
    print(b)
func(1)
func(1)
func(1)
func(1)
技术分享图片

看下结果

  [1]
  [1, 1]
  [1, 1, 1]
  [1, 1, 1, 1]

函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储,所以三次执行的结果就是 [1, 1, 1] ,想每次执行只输出[1] ,默认参数应该设置为None。

26、如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?

1 # encoding: utf-8
2 a = "1,2,3"
3 b = a.split(",")
4 print b

27、如何实现[‘1’,’2’,’3’]变成[1,2,3]?

1 >>>a = [1, 2, 3]
2 >>>b = [int(i) for i in a]
3 >>>b

28、a = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ]的区别?

a里面的元素都是int类型,b中的元素都是元组。

元组只有一个元素,必须要加逗号结尾

29、一行代码选出列表里面的不重复元素

1 b = [1,2,3,2,3,4,1,2]
2 print [i  for i in b if b.count(i)==1]
3 >>>4

30、logging模块的作用?以及应用场景

  日志是一种可以追踪某些软件运行时所发生事件的方法。

不同的应用程序所定义的日志等级可能会有所差别,分的详细点的会包含以下几个等级:

  • DEBUG
  • INFO
  • NOTICE
  • WARNING
  • ERROR
  • CRITICAL
  • ALERT
  • EMERGENCY
  • 技术分享图片

技术分享图片

 31、请用代码简答实现stack

技术分享图片
 1 stack的实现代码(使用python内置的list),实现起来是非常的简单,就是list的一些常用操作
 2 
 3 class Stack(object):
 4     def __init__(self):
 5         self.stack = []
 6 
 7     def push(self, value):    # 进栈
 8         self.stack.append(value)
 9 
10     def pop(self):  #出栈
11         if self.stack:
12             self.stack.pop()
13         else:
14             raise LookupError(‘stack is empty!‘)
15 
16     def is_empty(self): # 如果栈为空
17         return bool(self.stack)
18 
19     def top(self): 
20         #取出目前stack中最新的元素
21         return self.stack[-1]
技术分享图片
技术分享图片
 1 定义一个头结点,左边指向队列的开头,右边指向队列的末尾,这样就可以保证我们插入一个元素和取出一个元素都是O(1)的操作,使用这种链表实现stack也是非常的方便。实现代码如下:
 2 
 3 class Head(object):
 4     def __init__(self):
 5         self.left = None
 6         self.right = None
 7 
 8 class Node(object):
 9     def __init__(self, value):
10         self.value = value
11         self.next = None
12 
13 class Queue(object):
14     def __init__(self):
15         #初始化节点
16         self.head = Head()
17 
18     def enqueue(self, value):
19         #插入一个元素
20         newnode = Node(value)
21         p = self.head
22         if p.right:
23             #如果head节点的右边不为None
24             #说明队列中已经有元素了
25             #就执行下列的操作
26             temp = p.right
27             p.right = newnode
28             temp.next = newnode
29         else:
30             #这说明队列为空,插入第一个元素
31             p.right = newnode
32             p.left = newnode
33 
34     def dequeue(self):
35         #取出一个元素
36         p = self.head
37         if p.left and (p.left == p.right):
38             #说明队列中已经有元素
39             #但是这是最后一个元素
40             temp = p.left
41             p.left = p.right = None
42             return temp.value
43         elif p.left and (p.left != p.right):
44             #说明队列中有元素,而且不止一个
45             temp = p.left
46             p.left = temp.next
47             return temp.value
48 
49         else:
50             #说明队列为空
51             #抛出查询错误
52             raise LookupError(‘queue is empty!‘)
53 
54     def is_empty(self):
55         if self.head.left:
56             return False
57         else:
58             return True
59 
60     def top(self):
61         #查询目前队列中最早入队的元素
62         if self.head.left:
63             return self.head.left.value
64         else:
65             raise LookupError(‘queue is empty!‘)
技术分享图片

 32、常用字符串格式化哪几种?

技术分享图片
 1 一、使用%
 2 %s     字符串
 3 %c     字符
 4 %d     十进制(整数)
 5 %i     整数
 6 %u    无符号整数
 7 %o     八进制整数
 8 %x    十六进制整数
 9 %X     十六进制整数大写
10 %e     浮点数格式1 
11 %E     浮点数格式2 
12 %f     浮点数格式3 
13 %g    浮点数格式4 
14 %G    浮点数格式5 
15 %%     文字% 
16 >>> print("我叫%s,今年%d岁了" % ("小李", 20))
17 我叫小李,今年20岁了
技术分享图片
技术分享图片
二、通过{}替代%
1、正常使用
>>> print("我叫{},今年{}岁了".format("小李", 20))
我叫小李,今年20岁了
2、还可以通过在括号里填写数字,修改格式化的顺序
>>> print("我叫{1},今年{0}岁了".format("小李", 20))
我叫20,今年小李岁了
3、通过key取变量
>>> print("我叫{name},今年{age}岁了".format(name="小李", age=20))
我叫小李,今年20岁了
4、传入对象
>>> class Person:
...     def __init__(self,name,age):
...
...             self.name,self.age = name,age
...     def __str__(self):
...
...             return 我叫{self.name}, 今年{self.age}岁了.format(self=self)
>>> str(Person(小李,20))
我叫小李, 今年20岁了
5、通过下标
>>> person=[小李,20]
>>> 我叫{0[0]}, 今年{0[1]}岁了.format(person)
我叫小李, 今年20岁了
技术分享图片

33、简述 生成器、迭代器、可迭代对象 以及应用场景?

Python可迭代对象(Iterable) 
Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,像常见的list,tuple都是。如果给一个准确的定义的话,就是只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下标索引的__getitem__方法(这些双下划线方法会在其他章节中全面解释),那么它就是一个可迭代对象。

Python迭代器(iterator) 
迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义了这个方法的都算是迭代器。可以用通过下面例子来体验一下迭代器:

生成器(Generators) 
生成器是构造迭代器的最简单有力的工具,与普通函数不同的只有在返回一个值的时候使用yield来替代return,然后yield会自动构建好next()iter()

因为迭代器如此普遍,python专门为for关键字做了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。

技术分享图片
 1 1.3 定义迭代器 
 2 下面一个例子——斐波那契数列
 3 # -*- coding: cp936 -*-
 4 class Fabs(object):
 5     def __init__(self,max):
 6         self.max = max
 7         self.n, self.a, self.b = 0, 0, 1  #特别指出:第0项是0,第1项是第一个1.整个数列从1开始
 8     def __iter__(self):
 9         return self
10     def next(self):
11         if self.n < self.max:
12             r = self.b
13             self.a, self.b = self.b, self.a + self.b
14             self.n = self.n + 1
15             return r
16         raise StopIteration()
17 
18 print Fabs(5)
19 for key in Fabs(5):
20     print key
21 
22 结果
23 <__main__.Fabs object at 0x01A63090>
24 1
25 1
26 2
27 3
28 5
技术分享图片

34、用Python实现一个二分查找的函数

技术分享图片
 1 #!usr/bin/env python  
 2 #encoding:utf-8  
 3 def binary_search(num_list, x):
 4     ‘‘‘
 5     二分查找
 6     ‘‘‘
 7     num_list=sorted(num_list)
 8     left, right = 0, len(num_list)
 9     while left < right:
10         mid = (left + right) / 2
11         if num_list[mid] > x:
12             right = mid
13         elif num_list[mid] < x:
14             left = mid + 1
15         else:
16             return 待查元素{0}在列表中下标为:{1}.format(x, mid)
17     return  待查找元素%s不存在指定列表中%x
18  
19 if __name__ == __main__:
20     num_list = [34,6,78,9,23,56,177,33,2,6,30,99,83,21,17]
21     print binary_search(num_list, 34)
22     print binary_search(num_list, 177)
23     print binary_search(num_list, 21)
24     print binary_search(num_list, 211)
25     print binary_search(num_list, 985)
26 》》》
27 待查元素34在列表中下标为:9
28 待查元素177在列表中下标为:14
29 待查元素21在列表中下标为:5
30 待查找元素211不存在指定列表中
31 待查找元素985不存在指定列表中
技术分享图片

35、谈谈你对闭包的理解。

技术分享图片
 1 #闭包函数的实例
 2 # outer是外部函数 a和b都是外函数的临时变量
 3 def outer( a ):
 4     b = 10
 5     # inner是内函数
 6     def inner():
 7         #在内函数中 用到了外函数的临时变量
 8         print(a+b)
 9     # 外函数的返回值是内函数的引用
10     return inner
11 
12 if __name__ == __main__:
13     # 在这里我们调用外函数传入参数5
14     #此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
15     # 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
16     demo = outer(5)
17     # 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量
18     # demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
19     demo() # 15
20 
21     demo2 = outer(7)
22     demo2()#17
技术分享图片

36、os和sys模块的作用

os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;

sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。

技术分享图片
 1 os 常用方法
 2 
 3 
 4 os.remove(‘path/filename’) 删除文件
 5 
 6 os.rename(oldname, newname) 重命名文件
 7 
 8 os.walk() 生成目录树下的所有文件名
 9 
10 os.chdir(dirname) 改变目录
11 
12 os.mkdir/makedirs(dirname)创建目录/多层目录
13 
14 os.rmdir/removedirs(dirname) 删除目录/多层目录
15 
16 os.listdir(dirname) 列出指定目录的文件
17 
18 os.getcwd() 取得当前工作目录
19 
20 os.chmod() 改变目录权限
21 
22 os.path.basename(‘path/filename’) 去掉目录路径,返回文件名
23 
24 os.path.dirname(‘path/filename’) 去掉文件名,返回目录路径
25 
26 os.path.join(path1[,path2[,...]]) 将分离的各部分组合成一个路径名
27 
28 os.path.split(path) 返回( dirname(), basename())元组
29 
30 os.path.splitext() 返回 (filename, extension) 元组
31 
32 os.path.getatime\ctime\mtime 分别返回最近访问、创建、修改时间
33 
34 os.path.getsize() 返回文件大小
35 
36 os.path.exists() 是否存在
37 
38 os.path.isabs() 是否为绝对路径
39 
40 os.path.isdir() 是否为目录
41 
42 os.path.isfile() 是否为文件
43 
44 
45 sys 常用方法
46 
47 
48 sys.argv 命令行参数List,第一个元素是程序本身路径
49 
50 sys.modules.keys() 返回所有已经导入的模块列表
51 
52 sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息
53 
54 sys.exit(n) 退出程序,正常退出时exit(0)
55 
56 sys.hexversion 获取Python解释程序的版本值,16进制格式如:0x020403F0
57 
58 sys.version 获取Python解释程序的版本信息
59 
60 sys.maxint 最大的Int值
61 
62 sys.maxunicode 最大的Unicode值
63 
64 sys.modules 返回系统导入的模块字段,key是模块名,value是模块
65 
66 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
67 
68 sys.platform 返回操作系统平台名称
69 
70 sys.stdout 标准输出
71 
72 sys.stdin 标准输入
73 
74 sys.stderr 错误输出
75 
76 sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息
77 
78 sys.exec_prefix 返回平台独立的python文件安装的位置
79 
80 sys.byteorder 本地字节规则的指示器,big-endian平台的值是big,little-endian平台的值是little
81 
82 sys.copyright 记录python版权相关的东西
83 
84 sys.api_version 解释器的C的API版本
技术分享图片

37、谈谈你对面向对象的理解?

技术分享图片
在我理解,面向对象是向现实世界模型的自然延伸,这是一种“万物皆对象”的编程思想。在现实生活中的任何物体都可以归为一类事物,而每一个个体都是一类事物的实例。面向对象的编程是以对象为中心,以消息为驱动,所以程序=对象+消息。

面向对象有三大特性,封装、继承和多态。

封装就是将一类事物的属性和行为抽象成一个类,使其属性私有化,行为公开化,提高了数据的隐秘性的同时,使代码模块化。这样做使得代码的复用性更高。

继承则是进一步将一类事物共有的属性和行为抽象成一个父类,而每一个子类是一个特殊的父类--有父类的行为和属性,也有自己特有的行为和属性。这样做扩展了已存在的代码块,进一步提高了代码的复用性。

如果说封装和继承是为了使代码重用,那么多态则是为了实现接口重用。多态的一大作用就是为了解耦--为了解除父子类继承的耦合度。如果说继承中父子类的关系式IS-A的关系,那么接口和实现类之之间的关系式HAS-A。简单来说,多态就是允许父类引用(或接口)指向子类(或实现类)对象。很多的设计模式都是基于面向对象的多态性设计的。

总结一下,如果说封装和继承是面向对象的基础,那么多态则是面向对象最精髓的理论。掌握多态必先了解接口,只有充分理解接口才能更好的应用多态。
技术分享图片

38、面向对象深度优先和广度优先是什么?

请关注,未完待续!

38、面向对象深度优先和广度优先是什么?

技术分享图片

技术分享图片

 

技术分享图片

技术分享图片

 

39、面向对象中super的作用?

技术分享图片

40、是否使用过functools中的函数?其作用是什么?

技术分享图片
1 Python自带的 functools 模块提供了一些常用的高阶函数,也就是用于处理其它函数的特殊函数。换言之,就是能使用该模块对可调用对象进行处理。
2 
3 functools模块函数概览
4 functools.cmp_to_key(func)
5 functools.total_ordering(cls)
6 functools.reduce(function, iterable[, initializer])
7 functools.partial(func[, args][, *keywords])
8 functools.update_wrapper(wrapper, wrapped[, assigned][, updated])
9 functools.wraps(wrapped[, assigned][, updated])
技术分享图片

41、列举面向对象中带双下划线的魔术方法?

1. init()

2. del()

技术分享图片
1 在调用del方法的时候,实际使用的是del()
2 
3 class Person(object):
4     def __del__(self):
5         print(我给干掉啦)
6     
7 bill = Person()
8 del bill #我给干掉啦
技术分享图片

3. new()

技术分享图片
 1 new()只有继承自objectd的类才有new()这方法是在init()之前调用的,用于生成实例对象。多用于设计模式中的单例模式。单例模式是为了确保类有且只有一个对象。多用于日志记录和数据库操作,打印机后台处理程序。这样子可以避免对统一资源产生相互冲突的请求
 2 new()负责创建一个类的对象,init()方法负责对创建后的类对象进行默认设置
 3 class Singleton(object):
 4     def __new__(cls):
 5         if not hasattr(cls, instance):
 6             cls.instance = super(Singleton, cls).__new__(cls)
 7         return cls.instance
 8 
 9 s = Singleton()
10 print(Object created, s)
11 s1 = Singleton()
12 print(Object created, s1)
13 
14 # output
15 # Object created <__main__.Singleton object at 0x0000018EFF662DA0>
16 # Object created <__main__.Singleton object at 0x0000018EFF662DA0>
17 
18 cls是当前类,new()返回的是一个实例,和init()中的self是同一个东西
技术分享图片

42、如何判断是函数还是方法?

一般情况下,单独写一个def func():表示一个函数,如果写在类里面是一个方法。但是不完全准确。

技术分享图片
1 class Foo(object):
2     def fetch(self):
3         pass
4 
5 print(Foo.fetch)   # 打印结果<function Foo.fetch at 0x000001FF37B7CF28>表示函数
6 # 如果没经实例化,直接调用Foo.fetch()括号里要self参数,并且self要提前定义
7 obj = Foo()
8 print(obj.fetch)  # 打印结果<bound method Foo.fetch of <__main__.Foo object at 0x000001FF37A0D208>>表示方法
技术分享图片

43、面向对象中的property属性、类方法、静态方法?

property属性:

技术分享图片

类方法:

技术分享图片

 

静态方法:

技术分享图片

 44、列举面向对象中的特殊成员以及应用场景

技术分享图片
 1 1. __doc__
 2     表示类的描述信息
 3 class Foo:
 4     """ 描述类信息,这是用于看片的神奇 """
 5     def func(self):
 6         pass
 7 print Foo.__doc__
 8  
 9 ==============
10  描述类信息,这是用于看片的神奇
技术分享图片
1 2. __module____class__ 
2  __module__ 表示当前操作的对象在哪个模块
3    __class__     表示当前操作的对象的类是什么
1 3. __init__
2 构造方法,通过类创建对象时,自动触发执行。
1 4. __del__
2 析构方法,当对象在内存中被释放时,自动触发执行。
3 
4 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
5. __call__
  对象后面加括号,触发执行。
 
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
6. __dict__ 
  类或对象中的所有成员
7. __str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

8、__eq__

技术分享图片

 

45、什么是反射?以及应用场景?

技术分享图片

技术分享图片

技术分享图片

技术分享图片

技术分享图片

46、用尽量多的方法实现单例模式。

一、模块单例

Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。

技术分享图片
1 #foo1.py
2 class Singleton(object):
3     def foo(self):
4         pass
5 singleton = Singleton()
6 
7 #foo.py
8 from foo1 import singleton
技术分享图片

二、静态变量方法

先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式。

技术分享图片
 1 class Singleton(object):
 2     def __new__(cls,a):
 3         if not hasattr(cls, _instance):
 4             cls._instance = object.__new__(cls)
 5         return cls._instance
 6     def __init__(self,a):
 7         self.a = a
 8     def aa(self):
 9         print(self.a)
10 
11 a = Singleton("a")
技术分享图片

47、装饰器的写法以及应用场景。

技术分享图片

技术分享图片

48、异常处理写法以及如何主动跑出异常(应用场景)

技术分享图片

技术分享图片

49、isinstance作用以及应用场景?

技术分享图片

50、json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?

技术分享图片
 1 官方文档中的一个Demo:
 2 >>> import json
 3  
 4 >>> class ComplexEncoder(json.JSONEncoder):
 5 ...     def default(self, obj):
 6 ...         if isinstance(obj, complex):
 7 ...             return [obj.real, obj.imag]
 8 ...         return json.JSONEncoder.default(self, obj)
 9 ...
10 >>> dumps(2 + 1j, cls=ComplexEncoder)
11 [2.0, 1.0]
12 >>> ComplexEncoder().encode(2 + 1j)
13 [2.0, 1.0]
14 >>> list(ComplexEncoder().iterencode(2 + 1j))
15 [[, 2.0, , , 1.0, ]]
16  
技术分享图片
技术分享图片
 1 然后简单扩展了一个JSONEncoder出来用来格式化时间
 2 class CJsonEncoder(json.JSONEncoder):
 3  
 4     def default(self, obj):
 5         if isinstance(obj, datetime):
 6             return obj.strftime(%Y-%m-%d %H:%M:%S)
 7         elif isinstance(obj, date):
 8             return obj.strftime(%Y-%m-%d)
 9         else:
10             return json.JSONEncoder.default(self, obj)
11  
技术分享图片
1 使用时候只要在json.dumps增加一个cls参数即可:
2 
3 json.dumps(datalist, cls=CJsonEncoder)

51、json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?

技术分享图片

52、使用代码实现查看列举目录下的所有文件。

技术分享图片
1 import os
2 
3 if __name__ == __main__:
4     work_dir = C:\Program Files\MySQL\Connector ODBC 8.0
5     for parent, dirnames, filenames in os.walk(work_dir, followlinks=True):
6         for filename in filenames:
7             file_path = os.path.join(parent, filename)
8             print(文件名:%s % filename)
9             print(文件完整路径:%s\n % file_path)
技术分享图片

53、简述 yield和yield from关键字。

1、可迭代对象与迭代器的区别

可迭代对象:指的是具备可迭代的能力,即enumerable.  在Python中指的是可以通过for-in 语句去逐个访问元素的一些对象,比如元组tuple,列表list,字符串string,文件对象file 等。

迭代器:指的是通过另一种方式去一个一个访问可迭代对象中的元素,即enumerator。在python中指的是给内置函数iter()传递一个可迭代对象作为参数,返回的那个对象就是迭代器,然后通过迭代器的next()方法逐个去访问。

技术分享图片
1 from collections import Iterable
2 
3 li=[1,4,2,3]
4 iterator1 = iter(li)
5 print(next(iterator1))
6 print(next(iterator1))
7 print(next(iterator1))
8 print(isinstance(iterator1,Iterable)) # 判断是否是迭代器,导入collection模块
技术分享图片
>>>
1 4 2 True

2、生成器

生成器的本质就是一个逐个返回元素的函数,即“本质——函数”

最大的好处在于它是“延迟加载”,即对于处理长序列问题,更加的节省存储空间。即生成器每次在内存中只存储一个值

3、什么又是yield from呢?

简单地说,yield from  generator 。实际上就是返回另外一个生成器。如下所示:

技术分享图片
 1 def generator1():
 2     item = range(10)
 3     for i in item:
 4         yield i
 5 
 6 def generator2():
 7     yield a
 8     yield b
 9     yield c
10     yield from generator1() #yield from iterable本质上等于 for item in iterable: yield item的缩写版
11     yield from [11,22,33,44]
12     yield from (12,23,34)
13     yield from range(3)
14 
15 for i in generator2() :
16     print(i)
技术分享图片

从上面的代码可以看出,yield from 后面可以跟的式子有“ 生成器  元组 列表等可迭代对象以及range()函数产生的序列”

上面代码运行的结果为:

a
b
c
0
1
2
3
4
5
6
7
8
9
11
22
33
44
12
23
34
0
1
2

请关注,未完待续!

 

python高级进阶-网络编程和并发(?道题详解)

1、简述 OSI 七层协议。

OSI是Open System Interconnection的缩写,意为开放式系统互联。

OSI七层协议模型主要是:应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)。

技术分享图片
1、物理层
主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。   

2、数据链路层
定义了如何让格式化数据以进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。   

3、网络层
在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。   

4、运输层
定义了一些传输数据的协议和端口号(WWW端口80等),如: 
TCP(transmission control protocol –传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据) 
UDP(user datagram protocol–用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。   

5、会话层
通过运输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)   

6、表示层
可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例如,PC程序与另一台计算机进行通信,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另一台则使用美国信息交换标准码(ASCII)来表示相同的字符。如有必要,表示层会通过使用一种通格式来实现多种数据格式之间的转换。   

7、应用层
是最靠近用户的OSI层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。
技术分享图片

2、什么是C/S和B/S架构?

1. C/S架构及其背景

C/S架构是一种比较早的软件架构,主要应用于局域网内。在这之前经历了集中计算模式,随着计算机网络的进步与发展,尤其是可视化工具的应用,出现过两层C/S和三层C/S架构,不过一直很流行也比较经典的是我们所要研究的两层C/S架构。

C/S架构软件(即客户机/服务器模式)分为客户机和服务器两层:第一层是在客户机系统上结合了表示与业务逻辑,第二层是通过网络结合了数据库服务器。简单的说就是第一层是用户表示层,第二层是数据库层。客户端和服务器直接相连,这两个组成部分都承担着重要的角色。

技术分享图片

技术分享图片
2. C/S架构的优点
a. 客户端和服务器直接相连。点对点的连接方式更安全,可以直接操作本地文本,比较方便。
b. 客户端可以处理一些逻辑事务。可以进行数据处理和数据存储,提供一定的帮助。
c. 客户端直接操作界面。

3. C/S架构的缺点
a> C/S架构适用于局域网,对网速的要求比较高。
b> 客户端界面缺乏通用性,且当业务更改时就需要更改界面,重新编写。
c> 随着用户数量的增多,会出现通信拥堵、服务器响应速度慢等情况。
d> 系统的维护也比较麻烦。

4. C/S架构的应用
C/S架构的软件是在是数不胜数,从办公的OFFICE,WPS,WINRAR到杀毒软件如金山,瑞金再到我们的娱乐软件,如播放器,QQ,微信等,无处不见C/S架构。
技术分享图片

1. B/S架构及其背景
随着Internet和WWW的流行,以往的主机/终端和C/S都无法满足当前的全球网络开放、互连、信息随处可见和信息共享的新要求,于是就出现了B/S型模式,即浏览器/服务器结构。它是C/S架构的一种改进,可以说属于三层C/S架构。主要是利用了不断成熟的WWW浏览器技术,用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。
技术分享图片

第一层是浏览器(即客户端)只有简单的输入输出功能,处理极少部分的事务逻辑。由于客户不需要安装客户端,只要有浏览器就能上网浏览,所以它面向的是大范围的用户,所以界面设计得比较简单,通用。
第二层是WEB服务器,扮演着信息传送的角色。当用户想要访问数据库时,就会首先向WEB服务器发送请求,WEB服务器统一请求后会向数据库服务器发送访问数据库的请求,这个请求是以SQL语句实现的。
第三层是数据库服务器,它存放着大量的数据。当数据库服务器收到了WEB服务器的请求后,会对SQL语句进行处理,并将返回的结果发送给WEB服务器,接下来,WEB服务器将收到的数据结果转换为HTML文本形式发送给浏览器。

技术分享图片
2. B/S架构的优点
a> 浏览器和数据库服务器采用多对多的方式连接。因此适合在广域网里实现巨大的互联网,甚至是全球网,有着很强大的信息共享性。
b> 浏览器只处理一些简单的逻辑事务,负担小。
c> 数据都集中存放在数据库服务器,所以不存在数据不一致现象。
d> 随着服务器负载的增加,可以平滑地增加服务器的个数并建立集群服务器系统,然后在各个服务器之间做负载均衡。
e> B/S建立在广域网上,所以需要的网速要求不高。
f> 不需要安装客户端,只要能连上网,就能随时随地的浏览页面。
g> 能有效地保护数据平台和管理访问权限,确保服务器数据库的数据安全。

3. B/S架构的缺点
a> 服务器承担着重要的责任,数据负荷较重。一旦发生服务器“崩溃”等问题,后果不堪设想。
b> 页面需要不断地动态刷新,当用户增多时,网速会变慢。

4. B/S架构的应用
比如WEBQQ,从WEBQQ名称中的WEB就不难看出它属于B/S架构,是一种浏览器服务器结构。事实上也是如此,因为WEBQQ根本不需要安装客户端,只需要有浏览器就可以进行聊天交互了。
技术分享图片

3、简述 三次握手、四次挥手的流程。

三次握手:

初始状态:客户端A和服务器B均处于CLOSED状态,然后服务器B创建socket,调用监听接口使得服务器处于LISTEN状态,等待客户端连接。(后续内容用A,B简称代替)

1、A首先向B发起连接,这时TCP头部中的SYN标识位值为1,然后选定一个初始序号seq=x(一般是随机的),消息发送后,A进入SYN_SENT状态,SYN=1的报文段不能携带数据,但要消耗一个序号。

2、B收到A的连接请求后,同意建立连接,向A发送确认数据,这时TCP头部中的SYN和ACK标识位值均为1,确认序号为ack=x+1,然后选定自己的初始序号seq=y(一般是随机的),确认消息发送后,B进入SYN_RCVD状态,与连接消息一样,这条消息也不能携带数据,同时消耗一个序号。

3、A收到B的确认消息后,需要给B回复确认数据,这时TCP头部中的ACK标识位值为1,确认序号是ack=y+1,自己的序号在连接请求的序号上加1,也就是seq=x+1,此时A进入ESTABLISHED状态,当B收到A的确认回复后,B也进入ESTABLISHED状态,至此TCP成功建立连接,A和B之间就可以通过这个连接互相发送数据了。

四次挥手:

初始状态:客户端A和服务器B之间已经建立了TCP连接,并且数据发送完成,打算断开连接,此时客户端A和服务器B是等价的,双方都可以发送断开请求,下面以客户端A主动发起断开请求为例。(后续内容用A,B简称代替)

1、A首先向B发送断开连接消息,这时TCP头部中的FIN标识位值为1,序号是seq=m,m为A前面正常发送数据最后一个字节序号加1得到的,消息发送后A进入FNI_WAIT_1状态,FIN=1的报文段不能携带数据,但要消耗一个序号。

2、B收到A的断开连接请求需要发出确认消息,这时TCP头部中的ACK标识位值为1,确认号为ack=m+1,而自己的序号为seq=n,n为B前面正常发送数据最后一个字节序号加1得到的,然后B进入CLOSE_WAIT状态,此时就关闭了A到B的连接,A无法再给B发数据,但是B仍然可以给A发数据(此处存疑),同时B端通知上方应用层,处理完成后被动关闭连接。然后A收到B的确认信息后,就进入了FIN_WAIT_2状态。

3、B端应用层处理完数据后,通知关闭连接,B向A发送关闭连接的消息,这时TCP头部中的FIN和ACK标识位值均为1,确认号ack=m+1,自己的序号为seq=k,(B发出确认消息后有发送了一段数据,此处存疑),消息发送后B进入LACK_ACK状态。

4、A收到B的断开连接的消息后,需要发送确认消息,这是这时TCP头部中的ACK标识位值为1,确认号ack=k+1,序号为m+1(因为A向B发送断开连接的消息时消耗了一个消息号),然后A进入TIME_WAIT状态,若等待时间经过2MSL后,没有收到B的重传请求,则表明B收到了自己的确认,A进入CLOSED状态,B收到A的确认消息后则直接进入CLOSED状态。至此TCP成功断开连接。

 4、什么是arp协议?

ARP(Address Resolution Protocol)即地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址。

详细见 https://www.cnblogs.com/csguo/p/7527303.html

5、TCP和UDP的区别?

技术分享图片
TCP: 
TCP编程的服务器端一般步骤是: 
  1、创建一个socket,用函数socket(); 
  2、设置socket属性,用函数setsockopt(); * 可选 
  3、绑定IP地址、端口等信息到socket上,用函数bind(); 
  4、开启监听,用函数listen(); 
  5、接收客户端上来的连接,用函数accept(); 
  6、收发数据,用函数send()和recv(),或者read()和write(); 
  7、关闭网络连接; 
  8、关闭监听; 
技术分享图片
技术分享图片
UDP:
与之对应的UDP编程步骤要简单许多,分别如下: 
  UDP编程的服务器端一般步骤是: 
  1、创建一个socket,用函数socket(); 
  2、设置socket属性,用函数setsockopt();* 可选 
  3、绑定IP地址、端口等信息到socket上,用函数bind(); 
  4、循环接收数据,用函数recvfrom(); 
  5、关闭网络连接; 
技术分享图片

TCP与UDP基本区别

  1. 基于连接与无连接
  2. TCP要求系统资源较多,UDP较少
  3. UDP程序结构较简单
  4. 字节流模式(TCP)与数据报模式(UDP);
  5. TCP保证数据正确性,UDP可能丢包
  6. TCP保证数据顺序,UDP不保证

具体编程时的区别
        1.socket()的参数不同 
   2.UDP Server不需要调用listen和accept 
   3.UDP收发数据用sendto/recvfrom函数 
   4.TCP:地址信息在connect/accept时确定 
   5.UDP:在sendto/recvfrom函数中每次均 需指定地址信息 
   6.UDP:shutdown函数无效

6、什么是局域网和广域网?

局域网:(Local Area Network,LAN), 局域网是一个局部范围的计算计组,比如家庭网络就是一个小型的局域网,里面包含电脑、手机和平板等,他们共同连接到你家的路由器上。又比如学校的机房就是一个局域网,里面有几百几千台电脑,当机房无法上外网时,但是电脑之间仍可以通信,你们可以通过这个局域网来打CS 、玩红警。理论上,局域网是封闭的,并不可以上外网,可以只有两台电脑,也可以有上万台。

广域网:(WAN,Wide Area Network),广域网的范围就比较大了,可以把你家和别人家、各个省、各个国家连接起来相互通信。广域网和局域网都是从范围的角度来划分的,广域网也可以看成是很多个局域网通过路由器等相互连接起来。

7、为何基于tcp协议的通信比基于udp协议的通信更可靠?

TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。不过UDP的发送速度是TCP比不了的,而且UDP的反应速度更快。

8、什么是socket?简述基于tcp协议的套接字通信流程。

套接字,也称为BSD套接字,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。

1.服务器先用 socket 函数来建立一个套接字,用这个套接字完成通信的监听。 
2.用 bind 函数来绑定一个端口号和 IP 地址。因为本地计算机可能有多个网址和 IP,每一个 IP 和端口有多个端口。需要指定一个 IP 和端口进行监听。 
3.服务器调用 listen 函数,使服务器的这个端口和 IP 处于监听状态,等待客户机的连接。 
4.客户机用 socket 函数建立一个套接字,设定远程 IP 和端口。 
5.客户机调用 connect 函数连接远程计算机指定的端口。 
6.服务器用 accept 函数来接受远程计算机的连接,建立起与客户机之间的通信。 
7.建立连接以后,客户机用 write 函数向 socket 中写入数据。也可以用 read 函数读取服务器发送来的数据。 
8.服务器用 read 函数读取客户机发送来的数据,也可以用 write 函数来发送数据。 
9.完成通信以后,用 close 函数关闭 socket 连接。

技术分享图片

9、什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

技术分享图片

10、IO多路复用的作用?

一、基本概念

  IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:

  (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。

  (2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。

  (3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。

  (4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。

  (5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。

  与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

请关注,未完待续!

 

史上最全python面试题详解(附带详细答案(关注、持续更新))

原文:https://www.cnblogs.com/abdm-989/p/12129808.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!