python 面试题汇总 基础篇答案整理(80 题)

面试题汇总

题目来源

第一部分 Python 基础篇(80 题)

  1. 为什么学习 Python?

    语言本身简洁,优美,功能超级强大
    跨平台 
    是未来科技着重发展的方向, 例如机器学习、 深度学习、人工智能 有广阔的前景
    
  2. 通过什么途径学习的 Python?

    系统的视频教程,官方文档,和其他网站教程文档(如 runoob),开源代码(如github、gitee)
    
  3. Python 和 Java、PHP、C、C#、C++ 等其他语言的对比?

    python Java 解释型语言    c c++ 为编译型语言
    python java c++ 为面向对象语言
    PHP 开源的脚本语言 只适用于网页编程,而Python适合于各个领域。
    1.难易度而言。python远远简单于java、C#。
    2.开发速度。Python远优于java、C#
    3.运行速度。java、C#远优于标准python,pypy和cython可以追赶java,但是两者都没有成熟到可以做项目的程度。
    4.可用资源。java、C#资源丰富,python很少很少,尤其是中文资源。
    5.稳定程度。python3和2不兼容,造成了一定程度上的混乱以及大批类库失效。java、C#由于有企业在背后支持所以稳定的多。
    6.是否开源。python从开始就是完全开源的。Java由sun开发,但现在有GUN的Openjdk可用,C#也在逐渐开源。
    7.编译还是解释。都是解释型。
    
  4. 简述解释型和编译型编程语言?

    解释型语言 便翻译边执行,执行速度慢、效率低;依赖解释器、跨平台性好。
    编译型编程语言,把源程序全部都编译成机器语言,并保存成二进制文件执行。速度快、效率高;依赖编译器、跨平台性差些。
    
  5. Python 解释器种类以及特点?

    CPython
    当 从Python官方网站下载并安装好Python2.7后,就直接获得了一个官方版本的解释器:Cpython,这个解释器是用C语言开发的,所以叫 CPython,在命名行下运行python,就是启动CPython解释器,CPython是使用最广的Python解释器。
    /headIPython
    IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方式上有所增强,但是执行Python代码的功能和CPython是完全一样的,好比很多国产浏览器虽然外观不同,但内核其实是调用了IE。
    PyPy
    PyPy是另一个Python解释器,它的目标是执行速度,PyPy采用JIT技术,对Python代码进行动态编译,所以可以显著提高Python代码的执行速度。
    Jython
    Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。
    IronPython
    IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。
    在Python的解释器中,使用广泛的是CPython,对于Python的编译,除了可以采用以上解释器进行编译外,技术高超的开发者还可以按照自己的需求自行编写Python解释器来执行Python代码,十分的方便!
    
  6. 位和字节的关系?

    一个字节等于8位
    
  7. b、B、KB、MB、GB 的关系?

    8 b = 1 B   1024 B = 1 KB  1024KB = 1 MB   1024 MB = 1 GB
    
  8. 请至少列举 5 个 PEP8 规范(越多越好)。

    1. 导入模块: 导入不同模块单独起一行, 同模块的类,可多个导入;不使用 星号导入所有
    2.  同一行不以分号分隔写多个语句
    3. 代码间隔:赋值或运算操作符,两边空, 关键字传参不需要空格;闭合符号相邻不留空;内部模块和第三方模块空一行 ,导入操作和代码空两行;类之间空一行, 函数或方法之间空一行
    4. 变量命名: 驼峰命名法和下划线命名, 类名首字母大写, 函数名首字母小写
    5. 缩进使用四个空格, 不与制表符混用
    
  9. 通过代码实现如下转换:

    二进制转换成十进制:v = “0b1111011”
    十进制转换成二进制:v = 18
    八进制转换成十进制:v = “011”
    十进制转换成八进制:v = 30
    十六进制转换成十进制:v = “0x12”
    十进制转换成十六进制:v = 87

    v = "0b1111011"
    print('二进制 "0b1111011" 转换十进制等于:',int(v, 2))
    v = 18
    print("整数 18 转二进制等于:", bin(v))
    v = "011"
    print('八进制 "011" 转换十进制等于:',int(v, 8))
    v = 30
    print("整数 30 转换八进制等于:", oct(v))
    v = "0x12"
    print('十六进制 "0x12" 转换十进制等于:',int(v, 16))
    v = 87
    print("整数 18 转十六进制等于:", hex(v))
    
  10. 请编写一个函数实现将 IP 地址转换成一个整数。

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

    ip = "10.3.9.12"
    ips = ip.split('.')
    # 遍历对每个ip字段转换二进制以"0"补全八位 
    res = int("".join([bin(int(d))[2:].rjust(8, '0') for d in ips]), 2)
    print(res)
    
  11. python 递归的最大层数? 递归的最大深度默认是1000 层

    实际运用: python2 都可以递归计算到999,python3只能递归到998
    
    import sys
    print(sys.getrecursionlimit()) 
    # 获取默认递归深度sys.setrecursionlimit(自定义深度) 
    # 手动设置递归深度## 递归深度测试
    def fn(n):    
        if n==1:        
            return 1    
        else:         
            return fn(n-1)
    
    fn(1000) # 出错
    fn(998) # 输出1
    
  12. 求结果:

    v1 = 1 or 3                     # 结果 1 
    
    v2 = 1 and 3                  # 结果3 
    
    v3 = 0 and 2 and 1       # 返回0 
    
    v4 = 0 and 2 or 1          # 返回1 
    
    v5 = 0 and 2 or 1 or 4  # 返回1 
    
    v6 = 0 or Flase and 1   # 返回 Flase
    
    扩展1: or 返回第一个True的值,没有返回最后一个值, and 返回第一个False值,没有返回最后的正确值,因为or优先级最低发现正确的值就不再判断, and发现错误的值就不做and的判断,优先级: not > and > or
    扩展2: 值为False的值: 空序列类型: [] () {} ’’ "" 空数值类型: 0 -0 0j 0.0 空值:None
    
  13. asciiunicodeutf-8gbk 区别?

    ascii:
    美国信息交换标准代码(American Standard Code for Information Interchange),128个字符(0-127)的英文字符编码一个字符对应一个字节
    
    GBK:
    GB2312 是对 ASCII 的中文扩展GBK 包括了 GB2312 的所有内容,同时又增加了近 20000 个新的汉字(包括繁体字)和符号,                                
    GB18030 包含了GBK的所有,扩展了几千个新的少数民族的字,通称他们叫做 “DBCS”(Double Byte Charecter Set 双字节字符集)                
    汉字一个字符 两个字节 英文一个字符一个字节
    
    unicode
    ISO包括了地球上所有文化、所有字母和符号的编码!他们打算叫它 “Universal Multiple-Octet Coded Character Set”,简称 UCS。从 UNICODE 开始,无论是半角的英文字母,还是全角的汉字,都统一的 “一个字符”,即 “两个字节”
    
    utf-8 
    使用最广的一种unicode实现方式utf-8 面向传输的众多 UTF(UCS Transfer Format)标准之一 每次传输8个位为了核对双方对于高低位的认识是否是一致的,采用了一种很简便的方法,就是在文本流的开始时向对方发送一个标志符——如果之后的文本是高位在位,那就发送 “FEFF”,反之,则发送 “FFFE”。
    
  14. 字节码和机器码的区别?

    机器码: 即原生码: 即计算机可直接读取的数据,可直接执行字节码:通过编译生成的程序和数据片段组成的二进制文件, 如.java通过编译生成二进制.class文件
    
  15. 三元运算规则以及应用场景?

    name = val1 if condition else val2用于 判断条件 设置不同值
    
  16. 列举 Python 2 和 Python 3 的区别?

    xrange 和 range : 2.x xrange 返回生成器, range 返回列表, 3.x 中 抛弃xrange , range 返回生成器
    xreadlines 和 readlines : 2.x xreadlines 返回生成器, readlines 返回列表, 3.x 中 抛弃xreadlines , readlines 返回生成器
    print: 2.x 中print 为关键字 直接跟字符串  3.x中 print为函数 需添加括号包含字符串
    raw_input()和input(): 2.x 中raw_input 输入字符串,返回字符串 input 输入数字,返回数字  3.x 中 只有input 输入任何类型默认为字符串,返回字符串
    编码方式: 2.x中 文件默认编码是ASCII,字符串默认也是ASCII  3.x 中 默认编码是utf-8, 内存里(也就是字符串) 是编码是unicode,即使声明了某种编码,在内存里还是unicode
    int 和 long: 2.x中 存在int和long 整型和长整型,int类型最大值不能超过sys.maxint  3.x 中只有int类型, 类似于2.x中的long
    比较运算符: 2.x 支持<>作为!=的同义词, 3.x 只支持!=, 不再支持<>
    字典类方法的返回值: 2.x中 是列表。最常用方法有keys, items和values。3.x中,所有以上方法的返回值改为动态试图
    元类的使用: 2.x中,可以通过在类的声明中定义metaclass参数,或者定义一个特殊的类级别(class-level)__metaclass__属性,来创建元类。3.x中,__metaclass__属性被取消了
    
  17. 用一行代码实现数值交换: a = 1 b = 2

    a, b = b, a
    
  18. Python3 和 Python2 中 intlong 的区别?

    2.x中 存在int和long 整型和长整型,int类型最大值不能超过sys.maxint  3.x 中只有int类型, 类似于2.x中的long
    
  19. xrangerange 的区别?

    python2 中, xrange返回一个生成器, range返回一个列表. 
    python3中, range返回一个生成器用于 迭代生成指定其实位置和步长的等差数列
    
  20. 文件操作时:xreadlinesreadlines 的区别?

    差别类似xrange 和 rangepython2 中, xreadlines 返回一个生成器, readlines 返回一个列表
    python3中, readlines 返回一个生成器用于 迭代逐行读取文件文本
    
  21. 列举布尔值为 False 的常见值?

    布尔值为False: 空序列类型: [] () {} '' "" numbers类型: 0 -0 0j 0.0 空值:None
    
  22. 字符串、列表、元组、字典每个常用的 5 个方法?

    字符串: str join len title split upper lower rjust
    元组: len tuple count index
    列表:len pop index insert append extend sort
    字典: items keys values getitem len
    
  23. lambda 表达式格式以及应用场景?

    lambda 参数1: 表达式 , map() filter()
    
  24. pass 的作用?

    未将来的实现代码预留位置, 使没有语句的函数不报错。

  25. *arg**kwarg 作用

    解包, *args 同时传多个位置参数, ** kwarg 同时传 多个关键字参数
    
  26. is== 的区别

    is 比较内存地址ui否相同, ==比较值是否相同
    
  27. 简述 Python 的深浅拷贝以及应用场景?

    以列表嵌套列表为例
    浅拷贝: 重新开辟空间存放元素地址,不包括嵌套列表内的元素
    深拷贝:重新开辟空间 存放元素, 包括嵌套列表内的元素
    即浅拷贝指仅仅拷贝数据集合的第一层数据,深拷贝指拷贝数据集合的所有层,
    运用: 浅拷贝 copy模块  copy函数, 切片, 
    深拷贝 copy模块的 deepcopy函数 
    
  28. Python 垃圾回收机制?

    python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略
    python里每一个东西都是对象,它们的核心就是一个结构体:PyObject
    typedef struct_object {
    int ob_refcnt;
    struct_typeobject *ob_type;
    } PyObject;
    PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少
    #define Py_INCREF(op) ((op)->ob_refcnt++) //增加计数
    #define Py_DECREF(op) \ //减少计数
    if (--(op)->ob_refcnt != 0) \
    ; \
    else \
    __Py_Dealloc((PyObject *)(op))
    当引用计数为0时,该对象生命就结束了。
    引用计数机制的优点:简单
    实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
    引用计数机制的缺点:维护引用计数消耗资源
    ## 循环引用
    # list1 = []
    # list2 = []
    # list1.append(list2)
    # list2.append(list1)
    list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。
    对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将引入新的回收机制。(标记清除和分代收集)
    
  29. Python 的可变类型和不可变类型?

    可变类型:list, set, dict不可变类型: numbers, string ,tuple,frozenset
    
  30. 求结果:

    v = dict.fromkeys(['k1','k2'],[])
    v['k1'].append(666) 
    print(v) 
    v['k1'] = 777 
    print(v)
    
    结果: {“k1”: 777, “k2”: [666]}说明:新建一个字典为{‘k1’:[], “k2”:[]} # 两个字典的value 指向同一个空列表第一步在做了添加操作, 两个表都填充上666第二步’k1’ 赋值, 重新指向 777
    
  31. 求结果:

    def num():
        return [Lambda x: i*x for i in range(4)]
    print([m(2) for m in num()])
    
    输出结果: [6,6,6,6]lambda x : i*x 函数的命名空间只有x 只有函数运行时才会获取 i 的值, 经过迭代最终的 i = 3函数改为 : [lambda x, i=i: x*i for i in range(4)] 这时的命名空间存在 x, i ,可以解决问题
    
  32. 列举常见的内置函数?

    dir()、 type()、 repr()、 exec()、 eval() getattr() isinstance() id() str() int() print() input() __import__()
    
  33. filtermapreduce 的作用?

    map是用同样方法把所有数据都改成别的..字面意思是映射..比如把列表的每个数都换成其平方..
    
    

reduce是用某种方法依次把所有数据丢进去最后得到一个结果..字面意思是化简..比如计算一个列表所有数的和的过程,就是维持一个部分和然后依次把每个数加进去..

filter是筛选出其中满足某个条件的那些数据..字面意思是过滤..比如挑出列表中所有奇数..

map(lambda x:x*x,[0,1,2,3,4,5,6])
[0, 1, 4, 9, 16, 25, 36] # 操作独立的元素 返回结果长度一致
reduce(lambda x,y:x+y,[0,1,2,3,4,5,6])
21 # 类似动态规划 将之前的计算结果用于后续计算
filter(lambda x:x&1,[0,1,2,3,4,5,6])
[1, 3, 5] # 判断筛选符合条件的元素

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

    print("\n".join([' '.join(["%dx%d=%d"%(x,y,x*y) for y in range(1,x+1)]) for x in range(1,10)]))
    
  2. 如何安装第三方模块?以及用过哪些第三方模块?

    pip install 模块名称, 使用过flask django pymysql pyjwt pyredis pymongo pyjwt flask-sqlalchemy
    
  3. 至少列举 8 个常用模块都有那些?

    re sys time datetime json hashlib range md5 os requests urllib
    
  4. rematchsearch 区别?

    match 重起始位置开始匹配, search 从任意位置开始匹配
    
  5. 什么是正则的贪婪匹配?

    .* 点匹配任何字符, *号表示0个或多个, 两个连接使用, 会以尽可能多匹配符合的
    
  6. 求结果: a. [i % 2 for i in range(10) ] b. ( i % 2 for i in range(10) )

    结果: a:一个列表 [0,1,0,1,0,1,0,1,0,1,] , b: 一个生成器 调用next() 方法逐个返回
    
  7. 求结果: a. 1 or 2 b. 1 and 2 c. 1 <(2==2) d. 1 < 2 == 2

    结果: a : 1 , b: 2 , c. True , d:True(2==2) 结果为True 
    python中 True 等于1 , False等于0
    python 中的链式比较, 相当于 1<2 and 2==2
    
  8. def func(a,b=[]) 这种写法有什么坑?

    形参指向的一个空列表,传入参数a的操作 会叠加存入b中, b保存的元素会积累添加无法释放
    默认参数可以设置为None 可以解决
    
  9. 如何实现 "1,2,3" 变成 ['1','2','3'] ?

    res = "1,2,3".split(",")
    
  10. 如何实现 ['1','2','3'] 变成 [1,2,3] ?

    [int(i) for i in ['1','2','3']]
    
  11. 比较: a = [1,2,3]b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?

    a 和 第一个 b 一样,是包含1,2,3的列表, 第二个是列表嵌套三个元组
    元组元素只有一个时,需添加一个逗号, 否则 和没有括号相当
    
  12. 如何用一行代码生成 [1,4,9,16,25,36,49,64,81,100] ?

    print([x*x for x in range(1,11)])
    
  13. 一行代码实现删除列表中重复的值 ?

    list(set([1,1,1,2,2,3,1,2,3,3,4,3,4,5,4,6,]))
    
  14. 如何在函数中设置一个全局变量 ?

    用 global关键字声明的 变量
    
  15. logging 模块的作用?以及应用场景?

    logging 模块 定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统
    并设置了不同的事件等级
    
  16. 请用代码简答实现 stack

    class mystack(object):    
    		def __init__(self):        
    				self.stack = []    
    		def getval(self):        
    				return self.stack.pop(0)    
    		def delval(self,value):        
    				self.stack.append(value)
    
  17. 常用字符串格式化哪几种?

    x = 1
    xx = 11
    print(f"花括号包含变量名{xx}")
    print("花括号占位映射{0},{1}".format(x,xx))
    print("百分号占位,%d"%x)
    
  18. 简述 生成器、迭代器、可迭代对象 以及应用场景?

    迭代器对象就是实现了iter() 和 next()方法的对象.其中iter()返回迭代器本身,而next()返回容器的下一个元素,在结尾处引发StopInteration异常.生成器和迭代器属于可迭代对象生成器包含__next__ 方法, 迭代器包含__iter__方法迭代器包含__iter__方法
    
  19. 用 Python 实现一个二分查找的函数。

    data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
    # 双指针法实现二分查找 
    def binary_search(dataset,find_num):
        l, r = 0, len(dataset)-1
        while l < r-1:
            mid = (l+r)//2
            if dataset[mid]>find_num:
                r = mid
            elif dataset[mid]< find_num:
                l = mid
            else:
                print("目标数字下标为%d"% mid)
                return mid
        print("找不到目标数值")
    # binary_search(data, 12)
    # binary_search(data, 13)
    # binary_search(data, 23)
    # binary_search(data, 25)
                
    
  20. 谈谈你对闭包的理解?

    在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
    
    一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束
    
  21. ossys 模块的作用?

    1. os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
    2. sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
    
  22. 如何生成一个随机数?

    random.randint(a,b)  # 生成a 到 b 范围内的随机数
    
  23. 如何使用 python 删除一个文件?

    import os 
    os.remove('path/filename')
    
  24. 谈谈你对面向对象的理解?

    封装: 将属性和方法封装到类的内部,将数据封装到类的内部,方便调用
    继承: 将类共同的方法提取到基类,提高代码的复用率 
    多态: 鸭子模型  新式类(广度优先) 经典类(深度优先) 
    
  25. Python 面向对象中的继承有什么特点?

    将类共同的方法提取到基类,提高代码的复用率 
    
    继承的特点:
    
    

  1、在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。有别于C#

  2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数

  3、Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
```

  1. 面向对象深度优先和广度优先是什么?

    经典类遵循深度优先的规则,新式类遵循广度优先的规则
    在 python3 中,都是遵循广度优先的规则,在 python2.7 以前,应该是遵循深度优先的的规则。两种规则没有优劣之分。
    深度优先原则: 从左到右 每个都往父类查找,找不到再去查找后面的
    广度优先原则:  先从左到右查询,查到就不再继续,当前类没有继续查找父类
    
  2. 面向对象中 super 的作用?

    super() 函数是用于调用父类(超类)的一个方法。 super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。 MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
     super() 方法的语法:   super(type[, object-or-type])
    
  3. 是否使用过 functools 中的函数?其作用是什么?

    functools模块
    1.  wraps  在装饰器拷贝被装饰函数的 __name__   __doc__  等
    2. partial 偏函数, 给函数添加固定参数
    3. reduce 在 Python2 中等同于内建函数 reduce
    函数的作用是将一个序列归纳为一个输出
    reduce(function, sequence, startValue)
    4. lru_cache  允许我们将一个函数的返回值快速地缓存或取消缓存。
    
  4. 列举面向对象中带双下划线的特殊方法,如:__new____init__

    **str repr  getattribute   setattribute getitem setitem delitem  all mro  exit  start  del  module  class  doc**  
    
  5. 如何判断是函数还是方法?

    from types import MethodType, FunctionType
     
    class Bar:
        def foo(self):
            pass
     
    def foo2():
        pass
     
    def run():
        print("foo 是函数", isinstance(Bar().foo, FunctionType))
        print("foo 是方法", isinstance(Bar().foo, MethodType))
        print("foo2 是函数", isinstance(foo2, FunctionType))
        print("foo2 是方法", isinstance(foo2, MethodType))
     
    if __name__ == '__main__':
        run()
    
  6. 静态方法和类方法区别?

    静态方法 用@staticmethod 装饰器修饰,可以被类和实例调用
    类方法 用@classmethod装饰器修饰 **必须带cls 参数,**只能被类调用
    
  7. 列举面向对象中的特殊成员以及应用场景

    1. `__doc__`:表示类的描述信息。
    2. `__module__`:表示当前操作的对象在那个模块;
    3. `__class__`:表示当前操作的对象的类是什么。
    4. `__init__`:构造方法,通过类创建对象时,自动触发执行。
    5. `__call__`:对象后面加括号,触发执行。
    6. `__dict__`:类或对象中的所有成员。
    7. `__str__`:如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。
    8. `__getitem__`、`__setitem__`、`__delitem__`:用于索引操作,如字典。以上分别表示获取、设置、删除数据。
    9. `__iter__`:用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 `__iter__`。
    
  8. 1、2、3、4、5 能组成多少个互不相同且无重复的三位数

    import itertools
    print(len(list(itertools.permutations('12345',3))))
    #5x4x3 = 60个
    
  9. 什么是反射?以及应用场景?

    反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!
    
    应用场景:当我们动态的输入一个模块名的时候就可以使用到反射。
    
    通过hasattr,getattr,delattr,setattr等四个函数来操作
    
  10. metaclass 作用?以及应用场景?

    元类 实例化结果是类 :orm
    
  11. 用尽量多的方法实现单例模式。

    在 Python 中用尽量多的方法实现单例模式

    1. 模块:Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
    2. 先执行了类的__new__方法(我们没写时,默认调用object.__ new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式。
    3. 原理:装饰器用来控制类调用__ call__方法
    4. 执行元类的__new__方法和__init__方法用来实例化类对象,__ call__ 方法用来对实例化的对象的实例即类的对象进行控制。__call__方法会调用实例类的 __new__方法,用于创建对象。返回对象给__call__方法,然后调用类对象的 __init__方法,用于对对象初始化 
    
  12. 装饰器的写法以及应用场景。

    ########################################
    # 装饰器使用 functools.wraps 修饰函数
    # 实现执行时间输出
    import time
    from functools import wraps
    
    def timethis(func):
        '''
         报告执行时间的装饰器
        '''
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(func.__name__, end-start)
            return result
        return wrapper
    ###########################################
    # 添加日志功能
    from functools import wraps
    import logging
    
    def logged(level, name=None, massage=None):
        """
        最外层套一层带参数的函数,接受参数可作用于内部装饰器函数上
        level 是日志等级
        name为日志名,没传入默认模块名
        message 为日志内容 ,没传入默认函数名
        """
        def decorate(func):
            logname = name if name else func.__module__
            log = logging.getLogger(logname)
            logmsg = message if message else func.__name__
            
            @wraps(func)
            def wrapper(*args, **kwargs):
                log.log(level,logmsg)
                return func(*args,**kwargs)
            return wrapper
        return decorate
    
  13. 异常处理写法以及如何主动跑出异常(应用场景)

    try/except 关键字 捕获并处理异常
    raise 关键字主动抛出异常
    
  14. 什么是面向对象的 mro

    Python是支持面向对象编程的,同时也是支持多重继承的。
    而支持多重继承,正是Python的方法解析顺序(Method Resoluthion Order, 或MRO)问题出现的原因所在。
    
  15. isinstance 作用以及应用场景?

    isinstance作用:来判断一个对象是否是一个已知的类型;
     isinstance(obj,type)  对象类型相同返回Ture 
    
  16. 写代码并实现:

    Given an array of integers, return indices of the two numbers such that they add up to a specific target.You may assume that each input would have exactly one solution, and you may not use the same element twice.
    Example: Given nums = [2, 7, 11, 15], target = 9,Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]
    
    class Solution:
        def twoSum(self, nums: List[int], target: int) -> List[int]:
            dic = dict()
            for i,n in enumerate(nums):
                if target-n in dic:
                    return [dic.get(target-n),i]
                dic[n] = i
    
  17. json 序列化时,可以处理的数据类型有哪些?如何定制支持 datetime 类型?
    可处理 列表和字典类型, 或字典和列表的嵌套

    # 自定义时间序列化转换器
    import json
    from json import JSONEncoder
    from datetime import datetime
    class ComplexEncoder(JSONEncoder):
        def default(self, obj):
            if isinstance(obj, datetime):
                return obj.strftime('%Y-%m-%d %H:%M:%S')
            else:
                return super(ComplexEncoder,self).default(obj)
    d = { 'name':'alex','data':datetime.now()}
    print(json.dumps(d,cls=ComplexEncoder))
    # {"name": "alex", "data": "2018-05-18 19:52:05"}
    
  18. json 序列化时,默认遇到中文会转换成 unicode,如果想要保留中文怎么办?

    ## dumps函数添加参数ensure_ascii 设置为False
    import json
    a=json.dumps({"ddf":"你好"},ensure_ascii=False)
    print(a) #{"ddf": "你好"}
    
  19. 什么是断言?应用场景?

    assert 断言, 判断一个条件,为真 不做任何事情,为假会抛出AssertError并且包含错误信息  
    运用: 
    - 防御性编程: 
    - 运行时检查程序逻辑:
    - 检查约定:“如果你传给我一个非空字符串,我保证传会字符串的第一个
    字母并将其大写。”
    - 程序常量:
    - 检查文档:
    在测试代码的时候使用断言也是可接受的,是一种很方便的单元测试方法
    
  20. 有用过 with statement 吗?它的好处是什么?

    - 上下文管理协议(Context Management Protocol):包含方法__enter__()和__exit__(),支持该协议的对象要实现这两个方法。
    - 上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__()和__exit__()方法。上下文管理器定义执行with语句时要建立的运行时上下文,负责执行with语句块上下文中的进入与退出操作。通常使用with语句调用上下文管理器,也可以通过直接调用其方法来使用。
    1. 执行 statement中的表达式;
    2. 不管是否执行过程中是否发生了异常,执行上下文管理器的__exit__()方法,__**exit__**()方法负责执行 “清理” 工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行了语句break/continue/return,则以None作为参数调用__exit__(None, None, None);如果执行过程中出现异常,则使用sys.exc_info得到的异常信息为参数调用__exit__(exc_type, exc_value, exc_traceback);
    3. 出现异常时,如果__exit__(type, value, traceback)返回 False,则会重新抛出异常,让with之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理
    
  21. 使用代码实现查看列举目录下的所有文件。

    import os 
    
    def list_all_files(cur_dir):
        _files = []
        # 列出当前目录下所有文件和目录
        list_files = os.listdir(cur_dir)
    	  for i in range(len(list_files)):
            path = os.path.join(cur_dir,list_files[i])
            if os.path.isfile(path):
                _files.append(path)
            if os.path.isdir(path):
                _files.extend(list_all_files(path)
        return _files
    
  22. 简述 yield 和 yield from 关键字。

    yield  函数中以yield 关键字来返回值,这该函数为一个生成器
       ps: 生成器,延时加载,节省空间
    yield from + 可迭代对象(list、tuple、range函数)返回另一个生成器
    
posted @ 2020-07-31 11:50  lghgo  阅读(78)  评论(0编辑  收藏  举报