美文网首页
Python面试题汇总

Python面试题汇总

作者: 寻觅的以诺 | 来源:发表于2020-06-06 18:32 被阅读0次

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

    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函数并没有运行。如下:

    [<function num.<locals>.<listcomp>.<lambda> at 0x000002A67F4E8488>, <function num.<locals>.<listcomp>.<lambda> at 0x000002A67F4E8400>, <function num.<locals>.<listcomp>.<lambda> at 0x000002A67F4E8510>, <function num.<locals>.<listcomp>.<lambda> 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))
    >>> <filter object at 0x0000020ADB68B2B0>
    >>> [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))
      >>> <generator object <genexpr> at 0x000001F6BA656A40>
      
      1. 函数中加yield。例如:
      def func():
          for i in range(10):
              yield i
      
      print(func())
      >>> <generator object func at 0x00000251C8716A40>
      
    • 迭代器
      任何实现了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面试题汇总

          本文链接:https://www.haomeiwen.com/subject/cixzzhtx.html