Python面试题汇总

申明:这里整理的面试题题目主要来源于网络搜集,答案根据自己实践整理修改。

1. 简述解释型语言和编译型语言区别

解释型:
在运行的时候将代码翻译成目标机器代码进行执行,每次执行都会进行翻译。现代解释型语言基本都会将源码翻译成中间字节码,然后在运行的时候将中间字节码翻译成目标机器代码进行执行。
编译型:
先编译成机器语言再执行,编译和执行是分开的。每次执行的时候不需要再编译。

2. Python解释器种类以及特点?

  • CPython
    c语言开发的 使用最广的解释器,默认使用的解释器。
  • JPython
    Java编写的,运行在Java上的解释器 直接把python代码编译成Java字节码执行。
  • IPython
    IPython 是一个 python 的交互式 shell,比默认的python shell 好用得多,支持变量自动补全,自动缩进,支持 bash shell 命令,内置了许多很有用的功能和函数。
  • PyPy
    Python编写的。目标是执行效率 采用JIT(Just In Time:即时编译技术,简单的例子就是对于循环里的语句不会每次循环的时候都重新翻译,而是一次性翻译然后存起来,等到执行到的时候就将已经翻译过来的机器码直接拿来使用)技术 对python代码进行动态编译,提高执行效率。但是由于是用Python编写,所以在启动的时候会比CPython解释器启动慢。
  • IronPython
    .net编写的,运行在微软 .NET 平台上的解释器,把python编译成. NET 的字节码。

3. 请至少列举5个 PEP8 规范(越多越好)。

  • 每一级缩进使用4个空格。
  • 所有行限制的最大字符数为79。
  • 顶层函数和类的定义,前后用两个空行隔开。
  • 类里的方法定义用一个空行隔开。
  • import通常在分开的行,例如:
推荐: import os

    import sys

不推荐:  import sys, os

4. 完成以下的进制转换

4.1 从10进制转成2、8、16进制

设v = 18

  • 10进制转2进制
print(bin(v))
  • 10进制转8进制
print(oct(v))
  • 10进制转16进制
print(hex(v))

4.2 从2、8、16进制转10进制

  • 2进制转10进制:v = "0b1111011"
print(int(v, 2))
  • 8进制转10进制:v = "011"
print(int(v, 8))
  • 16进制转10进制:v = "0x1c"
print(int(v, 16))

5. 请编写一个函数实现将IP地址转换成一个整数。

如 10.3.9.12 转换规则为:
10 -> 00001010
3 -> 00000011
9 -> 00001001
12 -> 00001100
再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?

def ip_transfer(ip):
    ip_items = ip.split('.')
    # 10进制转2进制 且 拼接
    s = ''.join(bin(int(item))[2::] for item in ip_items)
    return int(s, 2)


if __name__ == '__main__':
    print(ip_transfer("10.1.15.110"))

6. python递归的最大层数

由于python为了防止无限递归,设计了递归限制是998。
可以自行设置递归最大限制

import sys
sys.setrecursionlimit(100000)

7. ascii、unicode、utf-8、gbk区别

  • Ascii
    美国信息互换标准代码
  • Gbk
    在gb2312的基础上增加了汉字,而gb2312在ascii的基础上增加了汉字
  • Unicode
    是字符集
  • Utf-8
    是编码规则,是对unicode的一种实现,可以将unicode码对应再编码成1-4字节大小。

8. 字节码和机器码的区别

  • 字节码
    字节码是一种中间状态(介于源代码和目标机器代码之间)的二进制代码。需要转译成目标机器代码。
  • 机器码
    计算机可以直接执行的代码。

9. 列举 Python2和Python3的区别

  • Python2
    1. print "aa"
    2. 整数之间 / ,只保留整数部分
    3. 不等于 <>
  • Python3
    1. print("aa")
    2. 整数之间 / ,保留小数部分
    3. 不等于 !=

10. Python3和Python2中 int 和 long的区别

在py2中,long是作为长整型的,但在py3中,没有long了,int长度不受限制。

11. xrange和range的区别

  • xrange
    xrange只在Python2中有,返回的是一个可迭代对象,但并不是迭代器,因为没有实现next
    在Python3中没有xrange。
  • range
    在Python2中,range返回一个list。
    在Python3中,range类似于Python2中的xrange,返回的是一个可迭代对象,但也并不是迭代器,因为并没有实现next

在Python2中xrange比range快,因为range会直接生成一个list,会一开始就开辟一块需要的内存空间,当范围越大这个内存空间越大,而xrange则是惰性计算的。但是为什么开辟一块大的内存空间就会导致慢呢?

详细关于Py2中的xrange、Python3中的range对象,与迭代器之间的区别,见https://zhuanlan.zhihu.com/p/34157478](https://zhuanlan.zhihu.com/p/34157478)

Python3中的range比xrange要快很多,详见https://zhuanlan.zhihu.com/p/24873916

12. 文件操作时:xreadlines和readlines的区别

  • readlines
    将所有的都读到内存,生成一个list
  • xreadlines
    则返回一个迭代器,但是在py2.3之后就不推荐这么用了,取而代之的是下面这种,这种所需文件内容是自动从buffer中按照需要读取的。
For line in file:
#  Do somenthing

13. 字符串、列表、元组、字典每个常用的5个方法

  • 字符串
    1. join方法。如:
    print(''.join(['a', 'b']))
    >>> 'ab'
    
    1. split方法。如:
    print('ab,c'.split(','))
    >>> ['ab', 'c']
    
    1. strip方法。如:
    print('abc'.strip('c'))
    >>> ab
    
    1. lstrip/rstrip方法。去掉左/右端的字符。如:
    print('abc'.rstrip('c'))
    >>> ab
    
    1. count方法。计算字符串中的某个字符出现的次数。如:
    print('accbc'.count('c'))
    >>> 3
    
    1. find方法。找到这个字符返回下标,多个时返回第一个;不存在的字符返回-1。如:
    print('abc'.find('b'))
    >>> 1
    
  • 列表
    1. 切片。
    print(['a', 'b'][0:1])
    >>> a
    
    1. append(self, obj)
    l = [1,2]
    l.append(3)
    print(l)
    >>> [1,2,3]
    
    1. insert(self, index, obj)
    l = [1,2]
    l.insert(1, 3)
    print(l)
    >>> [1,3,2]
    
    1. pop(self, index)
    l = [1,2]
    l.pop(1)
    print(l)
    >>> [1]
    
    1. remove(self, obj)
    l = [1,2]
    l.remove(2)
    print(l)
    >>> [1]
    
  • 字典
  1. pop(key)
d = {'a':1, 'b':2}
d.pop('a')
print(d)
>>> {'b': 2}
  1. copy() 属于浅拷贝
d = {'a':1, 'b':2}
copy_d = d.copy()
print(copy_d)
>>> {'a': 1, 'b': 2}
  1. len(d)
d = {'a':1, 'b':[1]}
print(len(d))
>>> 2
  1. d.items() 返回由字典中的每一个键值对字典组成的列表
d = {'a':1, 'b':[1]}
print(d.items())
>>> dict_items([('a', 1), ('b', [1])])
  1. del d['key'] 删除指定的key对应的键值对
d = {'a':1, 'b':[1]}
del d['a']
print(d)
>>> {'b': [1]}

14. lambda表达式格式以及应用场景

lambda x: x+1

试用场景,不需要多次使用的地方,例如reduce、map、filter等。

15. pass的作用

没有实际意义,可以保持结构完整(当没想好要怎么写的时候就写个pass上去)

16. arg和*kwarg作用

可以获取未知个位置参数和关键字参数

17. is和==的区别

is比较的是id(存放的地址值就是) ==比较的是值

18. 简述Python的深浅拷贝以及应用场景

浅拷贝就是对引用的拷贝,深拷贝就是对资源的拷贝。
如下:b是浅拷贝,c是深拷贝。根据所打印的id值,可以看出来。

import copy

a = [1, [2, 3]]
b = copy.copy(a)
c = copy.deepcopy(a)
a[0] = 11
a[1].append(4)
print(a)
print(b)
print(c)
print(id(a[1]), id(b[1]), id(c[1]))
>>> [11, [2, 3, 4]]
>>> [1, [2, 3, 4]]
>>> [1, [2, 3]]
>>> 2127624863432 2127624863432 2127624889032

Python中,相同的数字或者字符串,都是引用的同一个地址,因此对于数字和字符串来说,无论通过赋值,浅拷贝还是深拷贝,同一个值永远用的是同一个内存地址。

应用场景:
当需要拷贝一份模板资料进行修改,就不能用浅拷贝,这样我用过了别人用的就可能会受到影响

19. Python垃圾回收机制

Python中的垃圾回收是以引用计数为主,利用标记清除算法解决引用计数的循环引用问题,通过分代收集提高标记清除的效率。
引用计数:
在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引用计数器(ob_refcnt)。程序在运行的过程中会实时的更新ob_refcnt的值,来反映引用当前对象的名称数量。当某对象的引用计数值为0,那么它的内存就会被立即释放掉。但是引用计数无法解决循环引用的问题,例如:

a=[] a.append(a)

标记--清除算法:

  • 标记阶段
    遍历所有的对象,如果是可达的(reachable),也就是还有对象引用它,那么就标记该对象为可达。
  • 清除阶段
    再次遍历对象,如果发现某个对象没有标记为可达,则将其回收。

分代回收:
在循环引用对象的回收中,整个应用程序会被暂停,为了减少应用程序暂停的时间,Python 通过“分代回收”(Generational Collection)以空间换时间的方法提高垃圾回收效率。

分代回收是基于这样的一个统计事实,对于程序,存在一定比例的内存块的生存周期比较短;而剩下的内存块,生存周期会比较长,甚至会从程序开始一直持续到程序结束。生存期较短对象的比例通常在 80%~90% 之间,这种思想简单点说就是:对象存在时间越长,越可能不是垃圾,应该越少去收集。这样在执行标记-清除算法时可以有效减小遍历的对象数,从而提高垃圾回收的速度。

python gc给对象定义了三种世代(0,1,2),每一个新生对象在generation zero中,如果它在一轮gc扫描中活了下来,那么它将被移至generation one,在那里他将较少的被扫描,如果它又活过了一轮gc,它又将被移至generation two,在那里它被扫描的次数将会更少。

详见:https://zhuanlan.zhihu.com/p/83251959

20. Python的可变类型和不可变类型

  • 可变类型
    list、set、dict
  • 不可变类型
    string、int、float、tuple、frozenset(不可变集合)

21. 求结果

题目:

v = dict.fromkeys(['k1','k2'],[])
v['k1'].append(666)
print(v)
v['k1'] = 777
print(v)

结果:

{'k1': [666], 'k2': [666]}
{'k1': 777, 'k2': [666]}

原因:
因为k1和k2对应的value是同一个list地址,当v['k1'].append(666)的时候,由于k1和k2指向的是同一个地址,所以k2对应的value和k1的一样。当v['k1'] = 777的时候,k1对应的value的地址变了,但是k2对应的值还是之前的list的地址,所以k1变成了777,k2还是[666]。

22. 求值

题目:

def num():
    return [lambda x:i*x for i in range(4)]
print([m(2) for m in num()])

结果:

[6, 6, 6, 6]

原因:
一般可能认为答案应该是[0, 2, 4, 6],但是由于Python闭包的延迟绑定的特性,答案变成了[6, 6, 6, 6]。
Python的延迟绑定其实就是只有当运行到该函数的时候,才会引用外部变量i,不运行的时候,并不是会去找i的值。
在当前的题目中,num()只是返回4个lambda对象组成的list,此时lambda函数并没有运行。如下:

[.. at 0x000002A67F4E8488>, .. at 0x000002A67F4E8400>, .. at 0x000002A67F4E8510>, .. at 0x000002A67F4E8598>]

当运行到[m(2) for m in num()]的时候,才会真正运行到lambda函数。此时,i已经是3了,所以实际上得到的结果是[6, 6, 6, 6]

23. 列举常见的内置函数

len、bin、hex、oct、dir、max、min、type、sorted、isinstance、issubclass

24. filter、map、reduce的作用

  • filter(function, iterable)
    根据function,将iterable中的不符合条件的过滤掉。filter返回一个迭代器。
    例如:
l = [1,2]
l = filter(lambda x: True if x==1 else False, l)

print(l)
print(list(l))
>>> 
>>> [1]
  • map(func, iterables)
    将func作用域
    iterables中的每个序列的参数,返回一个map对象,该map对象也是一个迭代器。
    例如:
l = map(lambda x,y :x+y, [1,2], [2,3])
print(list(l))
>>> [3, 5]
  • reduce(function, sequence, initial=None)
    function是一个接受2个参数的函数。将function累计地作用到sequence中的每个元素上,从左到右,将这个sequence的所有值计算成一个值。
    例如:
print(reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]))
# ((((1+2)+3)+4)+5)
>>> 15

25. 一行代码实现9*9乘法表

  • 这里用了f-string
print('\n'.join([' '.join([f'{y} * {x} = {x * y}' for y in range(1, x+1)]) for x in range(1,10)]))

26. 至少列举8个常用模块都有那些

os sys json time datetime random requests copy re...

27. re的match和search区别

  • match
    必须字符串的开头就匹配上。
  • search
    不需要字符串的开头就匹配上。匹配到结果后就返回

28. 什么是正则的贪婪匹配

贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。
例如:

import re

s = 'abbcbbc'
res1 = re.search(r'a.*c', s)
res2 = re.search(r'a.*?c', s)
print(res1[0])
print(res2[0])
>>> abbcbbc
>>> abbc

29. 求结果

  • 1 or 2
    1
  • 1 and 2
    1
  • 1 < (2==2)
    False
    因为(2==2)先执行
  • 1 < 2 == 2
    True
    因为Python可以链式比较,这里这句话是相当于(1<2) and (2==2)

30. def func(a,b=[]) 这种写法有什么坑

假如在调用的时候不给b传值,用默认的list,会造成所有默认的都是用同一个list
例如:

def func(a, b=[]):
    b.append(a)
    print(b)
func(1)
func(1)
>>> [1]
>>> [1, 1]

31. 如何实现 “1,2,3” 变成 [‘1’,’2’,’3’]

"1,2,3".split(',')

32. 如何实现[‘1’,’2’,’3’]变成[1,2,3]

l = ['1','2','3']
lis = list(map(lambda x:int(x), l))

33. 比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别

a是列表
b = [(1),(2),(3)] 虽然列表的每个元素加上了括号,但是当括号内只有一个元素并且没有逗号时,其数据类型是元素本身的数据类型
b2中的元素是tuple[元组]

34. 如何用一行代码生成[1,4,9,16,25,36,49,64,81,100]

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

35. 一行代码实现删除列表中重复的值

list0 = ['b', 'c', 'd', 'b', 'c', 'a', 'a']
print(list(set(list0)))

36. 如何在函数中设置一个全局变量

  • step1. 在全局作用域申明一个变量
  • step2. 在函数中,通过global关键字将该变量申明为全局变量。如果不申明,会被当成函数内的局部变量而报错。
    例如:
a = 1

def func():
    global a
    a += 1
func()
print(a)
>>> 2

37. logging模块的作用,以及应用场景

logging.debug(msg, *args, **kwargs)
logging.info(msg, *args, **kwargs)
logging.warning(msg, *args, **kwargs)
logging.error(msg, *args, **kwargs)
logging.critical(msg, *args, **kwargs)

作用:根据不同需要输出不同等级、详细程度不同的信息。
应用场景:网站运维,程序的实时监控。

38. 请用代码简答stack

class Stack():
    def __init__(self):
        self._stack = []

    def push(self, v):
        self._stack.append(v)

    def pop(self):
        try:
            return self._stack.pop()
        except IndexError:
            raise ValueError("empty stack")

    def is_empty(self):
        return bool(self._stack)

    def watch(self):
        return self._stack

39. 常用字符串格式化哪几种

  • %s %d
a= 'f'
print('%s' % a)
>>> f
  • f-string
a = 1
print(f'{a}+2={a+2}')
>>> 1+2=3
  • format
print('{name} am handsome boy.'.format(name="I"))
>>> I am handsome boy.

40. 生成器、迭代器、可迭代对象、应用场景

  • 生成器
    可以理解为是一种一边循环一边计算的数据类型。
    两种方式:
    1. 生成器表达式。例如:
    print(i for i in range(10))
    >>>  at 0x000001F6BA656A40>
    
    1. 函数中加yield。例如:
    def func():
        for i in range(10):
            yield i
    
    print(func())
    >>> 
    
  • 迭代器
    任何实现了iternext的对象就是迭代器。例如:
from collections import Iterator


class IterA:
    def __iter__(self):
        pass

    def __next__(self):
        pass

print(isinstance(IterA(), Iterator))
>>> True
  • 可迭代对象
    对象内部实现了iter()方法,并调用这个方法可返回一个迭代器对象。例如:
from collections import Iterable


class IterA:
    def __iter__(self):
        pass

print(isinstance(IterA(), Iterable))
>>> True

应用场景:优化代码,节省内存

41. 用Python实现一个二分查找的函数

def two_search(list, value):
    lindex = 0
    rindex = len(list) - 1
    cindex = (lindex + rindex) // 2  # / 在py3中是包括了小数部分的
    res = -1
    # 二分法唯一的一个问题是,当所求的数是最右边的时候,按照cindex = (lindex + rindex) / 2的方式,当cindex = lindex的时候会死循环
    if list[-1] == value:
        res = rindex
    else:
        while lindex != cindex or cindex == 0:
            if value == list[cindex]:
                res = cindex
                break
            elif value > list[cindex]:
                lindex = cindex
                cindex = (lindex + rindex) // 2
            else:
                rindex = cindex
                cindex = (lindex + rindex) // 2
    return res

l = [1, 2, 3, 4, 5, 6, 9, 19, 40]
print(two_search(l, 5))
>>>  4

42. 谈谈你对闭包的理解

  • 闭包可以使得我们能获取到外部函数的参数和局部变量。
  • 闭包的使用,可以减少全局变量的污染,因为当使用全局变量的时候,全局变量可以被其他的所有的函数修改。
  • 闭包在装饰器上也有应用,把被修饰的函数作为参数保存了下来。
  • 闭包的缺点:是常驻内存的,会对增大内存的使用量。

43. os和sys模块的作用

  • os
    os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
    os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
    os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
  • sys
    sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
    Sys.exit(n)退出程序
    Sys.version返回python解释器版本

44. 如何生成一个随机数

  • Random.random() 随机生成一个浮点数,但是不能指定范围
  • Random.uniform(start,stop)随机生成一个浮点数,可以指定范围
  • Random.randomint(start, stop)生成一个整形的随机数

45. 如何使用python删除一个文件

Os.remove()

46. 谈谈你对面向对象的理解

  • 面向对象是一种编程思想。思想是万物皆对象。所有物体可以归类,每个实际的东西就是对应的那个类别的实例。
  • 面向对象的编程是以对象为中心,以消息为驱动的,就是 程序=对象+消息。
  • 面向对象有三大特性:
    封装:将具体的对象封装成抽象的类,对外封装属性,但是提供使用接口,目的是降低复杂 度,加大安全性。
    继承:儿子继承爸爸的方法和属性,减少冗余代码。
    多态:通过多态可以实现用一个函数名调用不同内容的函数。分为静态多态性和动态多态性
    静态多态性:静态就是在执行之前python解释器已经知道要调用哪个函数了,多态就是我们不用管到底是操作的对象是什么类型的,多种形态都是可以进行这个运算的。
    动态多态性:编译时无法立即确定其处理方式 , 只有在执行时才确定处理方式 , 注意一定要同名

47. Python面向对象中的继承有什么特点

  1. 在新式类中,方法的调用按照C3算法:拓扑排序+最左优先原则。

48. 面向对象中super的作用

调用父类的方法

49. 是否使用过functools中的函数?其作用是什么

functools主要是一些python高阶函数相关的函数
reduce函数
作用是用传入的函数对序列的每个值递进式地计算,最终计算出一个值。

50. 列举面向对象中带双下划线的特殊方法。

  • new:实例化对象的时候被调用
  • dict:获取类或对象中的所有成员
  • getitemsetitemdelitem:通过 [] 被调用
  • getattrsetattrdelattr:通过 . 被调用
  • call:为了将一个实例当做函数一样调用,例如a是A的实例,让a()可以直接执行
  • str:打印实例的时候调用的,一般是return一个字符串。例如a=A(),print(a)就会执行

51. 如何判断是函数还是方法

在类中定义的函数就是方法

52. 静态方法和类方法区别

  • 静态方法:当类去调用方法的时候不用实例化实例就可以调用;参数设置上不需要传递表示实例的self参数;依赖于装饰器@staticmethod
  • 类方法:当类去调用的时候不用实例化;参数设置上,第一个表示实例的self参数被表示类的cls取代了;依赖于装饰器@classmethod
    这里的self和cls都只是大家默认的而已,改成任何别的字母都是可以的

53. 1、2、3、4、5 能组成多少个互不相同且无重复的三位数

count = 0
for i in range(1, 6):
    for j in range(1, 6):
        for k in range(1, 6):
            if i != j and j != k and i != k:
                count += 1
print(count)
>>> 60

54. 什么是反射?以及应用场景

它的核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动。
应用场景:当a写程序程序写到一半没写完,但是b写的会用到a中的函数或者类,b就可以通过反射机制写完自己的程序。

55. metaclass作用,以及应用场景

作用:
metaclass直译为元类
metaclasss可以作为类声明时候的一个参数,可以传入我们自定义的元类
元类相当于是类的类,Python中内置的元类是type
所以所有自定义的元类都需要继承自type
应用场景
可以控制类的调用,比方说当类中没有注释(doc)的时候,抛出异常之类,当类的名称命名规则不对的时候,抛出异常之类

56. 单例模式

是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

class Singleton:
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

57. 装饰器

特点:

  1. 不改变原函数的源代码
  2. 不改变原函数的调用

实现:
利用闭包、高阶函数、语法糖实现。

例如:


def wrapper(f):
    def inner(*args, **kwargs):
        print("before")
        f()
        print("after")
    return inner

@wrapper
def func():
    print(1)

func()
>>> before
>>> 1
>>> after

带参数的装饰器:
在wrapper外面再套一层函数来接受参数,并将wrapper方法返回。在语法糖调用的时候加上括号,并填入参数,就相当于在执行到@语法糖对应的语句之前先执行了outer(a="...")函数,而outer函数返回wrapper函数,这样在把参数通过outer(a="...")函数传递进去之后,又变成了@wrapper的形式。

def outer(a):
    def wrapper(f):
        def inner(*args, **kwargs):
            print("before")
            print("print outer's args: ", a)
            f()
            print("after")

        return inner
    return wrapper


@outer(a="outer")
def func():
    print(1)

应用场景:
性能测试、权限判断等

58. 什么是面向对象的mro

mro(method resolution order)方法解析列表
代表了新式类继承的顺序,具体是用了一个c3算法,就是拓扑排序+最左优先原则

59. isinstance作用以及应用场景

isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。

isinstance() 与 type() 区别:

type() 不会认为子类是一种父类类型,不考虑继承关系。

isinstance() 会认为子类是一种父类类型,考虑继承关系。

如果要判断两个类型是否相同推荐使用 isinstance()。

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

可以处理的数据类型:
string、int、list、tuple、dict、bool、null
支持datetime:

import json
import datetime

ret = datetime.datetime.now()


class CJsonEncoder(json.JSONEncoder):
    def default(self, obj):

        if isinstance(obj, datetime.date):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        else:
            return json.JSONEncoder.default(self, obj)

print(json.dumps(ret, cls=CJsonEncoder))

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

在序列化是将json.dumps中的默认参数ensure_ascii改为False就可以保留中文了
json.dumps(obj,ensure_ascii=False)

62. 什么是断言,应用场景

什么是断言:
断言是编程术语,表示为一些布尔表达式。如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。
应用场景:
在执行某些步骤前,先检查参数是否正确。

63. 有用过with statement吗,它的好处是什么

有用过,用来打开文件的时候使用。
好处:

  1. 解决异常退出时资源释放的问题; (不用try catch)
  2. 解决用户忘记调用close方法而产生的资源泄漏问题;(不用手动关闭)

64. 使用代码实现查看列举目录下的所有文件

import os
import sys

sys.setrecursionlimit(100000)

def pridir(path=os.getcwd()):
    list = os.listdir(path)
    if len(list) != 0:
        for i in list:
            newpath = path+os.sep+i
            if os.path.isdir(newpath):
                pridir(newpath)
            elif os.path.isfile(newpath):
                print(i)

pridir("D:\\rm")

65. 简述 yield和yield from关键字

  • yield:
    1.向外抛出value
    2.暂停等待外部send/next()恢复
    3.将send进来的值赋值

  • yield from
    yield from iterable本质上等于for item in iterable: yield item的缩写版

例如:

def fun_inner():
    i = 0
    while True:
        i = yield i

# outer的作用就是将传递进来的参数传给inner,并且把inner返回的传给调用outer的地方
def fun_outer():
    inner = fun_inner()
    inner.send(None)
    while True:
        a = inner.send(1)
        yield a

if __name__ == '__main__':
    outer = fun_outer()
    outer.send(None)
    for i in range(5):
        print(outer.send(i))

用yield from修改后如下:

def fun_inner():
    i = 0
    while True:
        i = yield i

def fun_outer():
    yield from fun_inner()

if __name__ == '__main__':
    outer = fun_outer()
    outer.send(None)
    for i in range(5):
        print(outer.send(i))

你可能感兴趣的:(Python面试题汇总)