Python面试宝典(附答案)

为了帮助大家更好的吸收和加强python知识,yuan老师特此完成一篇关于python最精华的面试题册,通过对这两年每一期毕业学生的实际面试题的收集和整理,代表着当前市场对于python的最实际的需求和前沿方向,希望能帮助到大家。

第一篇、Python基础

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
变量
基本数据类型 : 字符串 布尔 整型和浮点型  None
运算符
     短路运算、零值
重要数据类型:列表 字典 以及元组 集合 
     列表字典的基本用法
     可变类型和不可变类型
     列表推导式、字典推导式  
流程控制语句
     三元运算表达
函数
   内置函数
   高阶函数
   迭代器和生成器
   闭包和装饰器
常用模块: 随机数模块  正则   
面向对象

(1)基础语法

  1. 关于变量赋值:交换a和b两变量的值

    1
    2
    3
    4
    
    a = 1
    b = 2
    b, a = a, b
    print(a, b)
    
  2. 如何用多个变量接收列表或者元组的值

    1
    2
    
    a, *b = [1, 2, 3]
    print(a,b)
    
  3. 输入一个字符串, 返回倒序排列的结果 如: abcdef, 返回 fedcba

    s = "abcdef"
    print(s[::-1])
    
  4. 将"北京 上海 广州 深圳"转换为 “北京,上海,广州,深圳”

    1
    2
    3
    
    s = "北京 上海 广州 深圳"
    l = s.split(" ")
    print(",".join(l))
    
  5. 短路计算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    print(3 and 2)
    print(3 or 2)
    # 应用
    user = None
    def foo():
        # user = "yuan"
        return user or "root"
    
    print(foo())
    
  6. 0 or 1 and 5 的结果

    1
    2
    3
    4
    
    print(not 1)
    print(not 0)
    print(0 or 1 and 5)
    print(6 and not 1 and 5)
    
  7. 零值概念

    1
    2
    3
    4
    5
    6
    
    print(bool("0"))
    print(bool("-1"))
    print(bool("False"))
    print(bool(0))
    print(bool(-1))
    print(bool([0, 0, 0]))
    
  8. is和==的区别

    1
    2
    3
    4
    
    l1 = [1, 2, 3]
    l2 = [1, 2, 3]
    print(l1 == l2)
    print(id(l1) == id(l2))
    
  9. 将两个列表[1, 5, 7, 9],[2, 2, 6, 8]合并为[1, 2, 2, 5, 6, 7, 8, 9]

    1
    2
    3
    4
    5
    
    l1 = [1, 5, 7, 9]
    l2 = [2, 2, 6, 8]
    l1.extend(l2)
    l1.sort()
    print(l1)
    
  10. a = [1,2,3,4,5,6],a[::-3] 的结果是

1
2
a = [1, 2, 3, 4, 5, 6]
print(a[::-3]) # [6, 3]
  1. 列表去重再排序

    1
    2
    3
    4
    
    l = [1, 4, 5, 6, 6, 4, 2, 1]
    l2 = list(set(l))
    l2.sort()
    print(l2)
    
  2. s = ‘ajldjlajfdljfddd’,去重并从小到大排序输出’adfjl’

    s = "ajldjlajfdljfddd"
    l = list(set(list(s)))
    l.sort()
    print("".join(l))
    
  3. 列表和元组有什么不同?

    元组称为只读列表
    元组是可hash得,可以作为字典的键,列表不可以
    
  4. python中哪些是可变类型 ,哪些是不可变类型

    1
    2
    
    # 不可变数据类型: 字符串 整型浮点型 布尔类型 元组
    # 可变数据类型  :列表 字典 
    
  5. 解释下Python的深浅拷贝

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    # 案例1:变量赋值
    l1 = [1,2,3]
    l2 = l1 # 不是拷贝,完全指向一块内存空间
    print(id(l1))
    print(id(l2))
    l2[1] = 200
    print(l1)
    
    # 案例2
    l1 = [1, 2, 3]
    l2 = [4, 5, l1]
    l1[0] = 100
    print(l2)
    
    # 案例3:浅拷贝:两种方式:切片和copy方法
    l1 = [1,2,3,["yuan","alvin"]]
    l2 = l1.copy()  # 等同于l2 = l1[:]
    print(id(l1))
    print(id(l2))
    l2[1] = 200
    print(l1)
    l2[3][0] = "张三"
    print(l1)
    
    #案例4: 深拷贝
    import copy
    l1 = [1,2,3,["yuan","alvin"]]
    l2 = copy.deepcopy(l1)
    l2[3][0] = "张三"
    print(l1)
    
  6. 请合并下面两个字典 a = {“A”: 1, “B”: 2},b = {“C”: 3, “D”: 4}

    1
    2
    3
    4
    5
    
    a = {"A": 1, "B": 2}
    b = {"C": 3, "D": 4}
    
    a.update(b)
    print(a)
    
  7. python的三元运算表达

    1
    2
    3
    4
    5
    
    x = 20
    y = 30
    ret = x if x > y else y
    print(ret)
    print("x是一个偶数" if x % 2 == 0 else "x是一个奇数")
    
  8. 统计一段字符串中每个字符出现的次数,比如abcaabccab

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    # 方式1
    s = "abcaabccab"
    print(s.count("ab"))
    dic = {}
    for i in s:
        dic[i] = dic.get(i,0)+1
    print(dic)
    
    # 方式2
    s = "abcaabccab"
    result = {x: s.count(x) for x in s}
    print(result)
    
  9. 字典和列表的查找速度哪个更快?

    1
    
    列表查询是遍历方式,时间复杂度是O(n), 字典查询是hash映射 时间复杂度是O(1);当数据量小的时候切片查询比map快,但是数据量大的时候字典的优势就体现出来了
    
  10. 如何实现[‘1’, ‘2’, ‘3’]变成[1, 2, 3]

    1
    2
    3
    
    # [表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] ]
    l = ['1', '2', '3']
    print([int(i) for i in l])
    
  11. 获取1-100中所有偶数平方列表

    1
    
    print([i ** 2 for i in range(1, 101) if i % 2 == 0])
    
  12. 1,2,3,4,5能组成多少个互不相同且无重复的元素?

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    # 方式1
    li = [1, 2, 3, 4, 5]
    new_li = []
    
    for i in li:
        for j in li:
            for m in li:
                if i != j and i != m and j != m:
                    num_str = str(i) + str(j) + str(m)
                    num = int(num_str)
                    new_li.append(num)
    
    new_li.sort()
    print(new_li)
    
    # 方式2
    ret = [int(str(i) + str(j) + str(k)) for k in li for j in li for i in li if i != j and i != k and j != k]
    ret.sort()
    print(len(ret))
    print(ret)
    
  13. 如何交换字典 {“A”:1,“B”:2}的键和值

    1
    2
    3
    
    # { 新键值对 for 迭代变量 in 可迭代对象 [if 条件表达式] }
    d1 = {"A": 1, "B": 2}
    print({v: k for k, v in d1.items()})
    
  14. 将所有的key值变为大写

    1
    
    print({k.upper():v for k,v in d.items()})
    
  15. pass语句的作用是什么

    1
    
    占位语句,不执行任何操作
    
  16. 如何在一个函数内部修改全局变量

    1
    2
    3
    4
    5
    6
    7
    8
    
    x = 10
    
    def foo():
        global x
        x = 100
    
    foo()
    print(x)
    
  17. 如何修改一个非局部非全局变量

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    def foo():
        x = 10
    
        def bar():
            # print(count)
            # count = 10
    
    
            nonlocal x
            x = x + 1
    
        bar()
    foo()
    
  18. python的最大递归层数

    1
    2
    
    import sys
    print(sys.getrecursionlimit())
    
  19. 请解释使用 *args 和 **kwargs 的含义(补充*

    1
    2
    3
    4
    5
    6
    7
    
    *args 代表位置参数,它会接收任意多个参数并把这些参数作为元组传递给函数。
    
    **kwargs 代表的关键字参数,允许你使用没有事先定义的参数名。
    
    位置参数一定要放在关键字参数的前面。
    
    作用:使用*args和**kwargs可以非常方便的定义函数,同时可以加强扩展性,以便日后的代码维护。
    
  20. 实现一个反转整数的函数,例如 -123 –> -321

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    def reverse_str(value):
        if value > -10 and value < 10:
            return value
        val_str = str(value)
        if val_str[0] != "-":
            val_reverse = int(val_str[::-1])
        else:
            # -123
            val_reverse = -int(val_str[1:][::-1])
        return val_reverse
    
    print(reverse_str(112))
    
  21. python的函数传参是传值还是传址

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    def  foo(x):
        print(id(x))
        x = 20
        # x = []
        # x.append(10)
        print(id(x))
    
    # a = []
    a = 10
    print(id(a))
    foo(a)
    
  22. 对数值1.3425四舍五入保留2位小数点

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    # 常用的内置函数
    bool
    bin
    oct
    hex
    sum
    max
    min
    abs
    pow
    divmod  
    round
    chr
    ord
    list
    dict
    set
    len
    any
    all
    zip
    sorted #(最常考的)
    
    1
    
    print(round(1.3425, 2))
    
  23. sortet排序:_dict = {‘a’: 1, ‘b’: 2, ‘c’: 3},要求根据value值从大到小输出key

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    # 案例1
    l = [1, 4, 6, 2, 8, 3]
    print(sorted(l))
    
    # 案例2
    l2 = [("yuan", 22), ("rain", 33), ("alvin", 24)]
    print(sorted(l2, key=lambda item: item[1]))
    
    # 案例3
    _dict = {'a': 1, 'b': 2, 'c': 3}
    ret = sorted(_dict.items(), key=lambda x: x[1], reverse=True)
    print([i[0] for i in ret])
    
  24. 如何把元组(“a”,“b”)和元组(1,2),变为字典{“a”:1,“b”:2}

    1
    2
    3
    
    a = ("a", "b")
    b = (1, 2)
    print(dict(zip(a, b))) # {'a': 1, 'b': 2}
    
  25. 一条语句把 L=[(1,2), (3,4)] 转换成 [(1,3),(2,4)],可以写下不同的方法

    1
    2
    3
    4
    5
    
    L = [(1, 2), (3, 4)]
    
    print([j for i in L for j in i])  # [1, 2, 3, 4]
    print([(j[1], j[0]) for j in L])  # [(2, 1), (4, 3)]
    print(list(zip(L[0], L[1])))  # [(1, 3), (2, 4)]
    
  26. 合并所有二维列表元素到一个列表:l = [[1, 2], [3, 4], [5, 6]]

  27. 有个列表a = [1, 3, 5, 7, 0, -1, -9, -4, -5, 8] 使用filter 函数过滤出大于0的数

    1
    2
    3
    4
    
    a = [1, 3, 5, 7, 0, -1, -9, 4, -5, 8]
    print(list(filter(lambda x: x > 0, a)))
    # 思考如果过滤大于0的奇数
    print(list(filter(lambda x: x > 0 and x % 2 == 1, a)))
    
  28. 列表b = [“张三”, “张四”, “张五”, “王二”] 过滤掉姓张的姓名

    1
    
    print(list(filter(lambda x: not x.startswith("张"), b)))
    
   ```python
   # 过滤掉列表中不及格的学生
   a = [
           {"name": "张三", "score": 66},
           {"name": "李四", "score": 88},
           {"name": "王五", "score": 90},
           {"name": "陈六", "score": 56},
        ]
   
   # 返回
   print(list(filter(lambda x: x.get("score")>=60, a)))
   ```
  1. 请将列表 [1,2,3,4,5] 使用map函数转变成 [1,4,9,16,25]

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    l = [1, 2, 3, 4, 5]
    
    # 方案1
    print([i * i for i in l])
    
    
    # 方案2
    def foo(item):
        return item * item
    
    print(list(map(foo, l)))
    
    # 方案3
    print(list(map(lambda x: x * x, l)))
    
  2. map函数对列表a=[1,3,5],b=[2,4,6]相乘得到[2,12,30]

    1
    2
    3
    4
    5
    6
    7
    8
    
    a = [1, 3, 5]
    b = [2, 4, 6]
    
    # 方案1:
    print([i[0] * i[1] for i in zip(a, b)])
    
    # 方案2:
    print(list(map(lambda x, y: x * y, a, b)))
    
  3. 将 ‘python is shell’ 转为 ’nohtyp si llehs’

    1
    2
    3
    
    s = 'python is shell'
    
    print(" ".join(list(map(lambda x:x[::-1],s.split(" ")))))
    
  4. 关于迭代器、生成器

  5. range函数的用法

  6. 一行代码实现1-100的求和

    1
    
    print(sum(range(1,101)))
    
  7. xrange和range的区别?

    xrange在2版本就是3中range的作用,构建一个迭代器对象
    
  8. 如何最快读取5个G的文件的行数

    1
    
    print(max(len(x.strip()) for x in open('apple.py','r')))
    
  9. 关于生成器的面试题:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    def add(x,y):
        return  x+y
    
    def gen():
        for i in range(4):
            yield i
    
    base = gen()
    for n in [1, 10]:
        base = (add(i, n) for i in base)
    
    print(list(base))
    
  10. 聊一聊你对闭包的理解

  11. 是一个装饰器,计算某个函数被调用的次数

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    def cal_call(func):
        count = 0
    
        def inner():
            nonlocal count
            count = count + 1
            ret = func()
            print(f"已经调用{count}次")
    
        return inner
    
    
    @cal_call  # foo = cal_call(foo)
    def foo():
        print("foo")
    
    
    foo()
    foo()
    foo()
    foo()
    foo()
    
  12. 请实现一个装饰器, 限制该函数被调用的频率, 如10秒一次

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    import time
    
    
    def wrpper(func):
        last_call_time = 0
    
        def inner(*args, **kwargs):
            nonlocal last_call_time
            time_now = time.time()
            if time_now - last_call_time > 10:
                last_call_time = time_now  # 设置调用时间
                res = func(*args, **kwargs)
            else:
                delta = 10 - (time_now - last_call_time)
                print(f'函数 {func.__name__} can be used after {delta}s!')
                res = None
            return res
    
        return inner
    
    
    @wrpper
    def foo():
        print("foo")
    
    foo()
    time.sleep(8)
    foo()
    
  13. 解释什么样的语言能够用装饰器?

    函数可以作为参数使用的
    
  14. 从0-99这100个数中随机取出10个, 要求不能重复, 可以自己设计数据结构

    1
    2
    3
    
    import random
    li = range(1, 101)
    print(random.sample(li, 10))
    
  15. 如何随机打乱列表中元素

    1
    2
    3
    4
    5
    
    import random
    
    l = [1, 2, 3, 4, 5, 6, 7]
    random.shuffle(l)
    print(l)
    
  16. 输入某年某月某日,判断这一天是这一年的第几天?

    1
    2
    3
    4
    5
    6
    7
    
    import datetime
    
    date01 = datetime.date(2011, 12, 31)
    date02 = datetime.date(2012, 12, 12)
    
    print(date02.strftime("%j"))
    print((date02 - date01).days)
    
  17. 如何用python删除一个文件

    1
    
    os.remove("abc.py")
    
  18. 正则匹配以163.com或者qq的邮箱

    1
    2
    3
    4
    
    import re
    
    ret = re.findall("\w{4,20}@(?:qq|163)\.com", "916852314@qq.com,1052065089@163.com")
    print(ret)
    
  19. 字符串a = “not 404 found 张三 99 深圳”,每个词中间是空格,用正则的方法,最终输出"张三 深圳"

    1
    2
    3
    4
    5
    6
    
    import re
    
    str = "not 404 found 张三 99 深圳 中国"
    chinese = '[\u4e00-\u9fa5]+'
    str1 = re.findall(chinese, str)
    print(str1)
    
  20. 正则中 .*?的作用

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    # .*是贪婪匹配,会把满足正则的尽可能多的往后匹配
    
    # .*?是非贪婪匹配,会把满足正则的尽可能少匹配
    
    # 案例1
    import re
    
    ret = re.findall("\d+", "45 yuan 56 rain 18 34 alvin")
    print(ret)
    
    # 案例2
    import re
    # 对比两者的区别
    ret = re.findall("<div class='title'>.*</div>","<div><div class='title'>yuan</div></div>")
    ret = re.findall("<div class='title'>.*?</div>","<div><div class='title'>yuan</div></div>")
    print(ret)
    
  21. 序列化和反序列化

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    序列化 通过某种方式把数据结构或对象写入到磁盘文件中或通过网络传到其他节点的过程
    反序列化把磁盘中对象或者把网络节点中传输的数据恢复为python的数据对象的过程
    
        +-------------------+---------------+
        | Python            | JSON          |
        +===================+===============+
        | dict              | object        |
        +-------------------+---------------+
        | list, tuple       | array         |
        +-------------------+---------------+
        | str               | string        |
        +-------------------+---------------+
        | int, float        | number        |
        +-------------------+---------------+
        | True              | true          |
        +-------------------+---------------+
        | False             | false         |
        +-------------------+---------------+
        | None              | null          |
        +-------------------+---------------+
    
  22. __str____repr__的区别

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    # __str__ 的返回结果可读性强。也就是说,__str__ 的意义是得到便于人们阅读的信息
     # __repr__ 存在的目的在于调试,便于开发者使用
    
     # 案例1:
     class A():
    ...     def __str__(self):
    ...         return "str"
    ... 
    ...     def __repr__(self):
    ...         return "repr"
    ... a = A()
    a
    repr
    print(a)
    str
    
    # 案例2:
    
    s = "hello yuan"
    print(s)
    print(repr(s))   
    
    # 案例3:
    import datetime
    date = datetime.datetime.now()
    print(str(date))  # '2021-05-21 12:04:02.671735'
    print(repr(date)) # 'datetime.datetime(2021, 5, 21, 12, 4, 2, 671735)'
    
  23. __dir__的功能

    1
    2
    3
    
    提到了 dir() 函数,通过此函数可以某个对象拥有的所有的属性名和方法名,该函数会返回一个包含有所有属性名和方法名的有序列表。
    通过 dir() 函数,不仅仅输出本类中新添加的属性名和方法(最后 3 个),还会输出从父类(这里为 object 类)继承得到的属性名和方法名。
    __dict__:查出一个字典,所有实例共享的变量和函数,dir()的子集,只包含自己的属性,不显示继承的。
    
  24. __new____init__的作用

    1
    2
    3
    
    1. new在创建实例之前被调用,创建实例然后返回该实例对象,属于静态方法
    2. init是当实例对象创建完成后被调用的,设置对象的一些初始化值,属于实例方法
    3. 继承自object的新式类才能有new,new至少有一个参数cls,代表当前类
    
  25. 如何判断一个对象是否可调用

    1
    
    print(callable("yuan"))
    
  26. 关于面向对象的变量查找

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    class A(object):
        def __init__(self):
            self.foo()
    
        def foo(self):
            print("A foo")
    
    
    class B(A):
        foo = 100
    
        def foo(self):
            print("B foo")
    
        def __init__(self):
            # self.foo = 100
            super().__init__()
    
    
    b = B()
    
  27. 实现一个Singleton单例类, 要求遵循基本语言编程规范(用尽量多的方式)。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    # 方式1:基于__new__
    class Singleton(object):
        intance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls.intance:
                cls.intance = super().__new__(cls, *args, **kwargs)
    
            return cls.intance
    
    
    s1 = Singleton()
    s2 = Singleton()
    print(s1 == s2)
    
    
    # 方式2:基于模块的语法
    class Singleton(object):
        pass
    
    
    s1 = Singleton()
    
    print(id(s1))
    
    # 调用模块
    from demo import s1
    
    print(id(s1))
    
  28. python的私有变量如何设置

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    class Student(object):
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
    
    s = Student("yuan", 21)
    
    # print(s.name)
    # print(s.__name)
    # print(dir(s))
    # print(s._Student__name)
    
  29. 什么是c3算法?

  30. metaclass作用?以及应用场景?

    1
    2
    3
    4
    5
    
     """
     MetaClass是用来创建类的,就好比类是用来创建对象的。如果说类是对象的模板,那么metaclass就是类的模板。
     直接将需要的属性全部作为新组合类的成员列出来;
     分别将各个独立的属性集定义成单个的类,然后通过在组合类添加每个属性类的实例(instance)的方式来引用各个属性类      中定义的属性;
    """
    
  31. 什么是反射?以及应用场景?(核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动)

    1
    2
    3
    4
    5
    6
    7
    8
    
    反射的概念是由Smith在1982年首次提出的主要是指程序可以访问检测和修改它本身状态或行为的一种能力自省)。
    python面向对象中的反射通过字符串的形式操作对象相关的属性python中的一切事物都是对象都可以使用反射
    
    四个实现反射的函数
    hasattr(object,name)   # 判断object中有没有一个name字符串对应的方法或属性
    getattr(object, name, default=None)   # 获取属性
    setattr(x, y, v)   # 设置属性
    delattr(x, y)   # 删除属性
    
  32. 什么是断言(assert)?应用场景?

    1
    
    assert(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,assert用于保证程序最基本、关键的正确性。assert 检查通常在开发和测试时开启。为了提高性能,在软件发布后, assert检查通常是关闭的。在实现中,断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式计算为false,那么系统会报告一个Assertionerror。
    
  33. ascii、unicode、utf-8、gbk 区别?

  34. Python垃圾回收机制

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    
    # python采用的是以引用计数为主,以分代回收和标记清除为辅的垃圾回收机制
    
    # 1 引用计数
    """
    在python中,每创建一个对象,那么python解释器会自动为其设置一个特殊的变量,这个变量称为引用计数(初始值默认是1)。一旦有一个新变量指向这个对象,那么这个引用计数的值就会加1。如果引用计数的值为0。那么python解释器的内存管理系统就会自动回收这个对象所占的内存空间,删除掉这个对象。
    引用计数+1的情况:
        对象被创建,例如a = "yuan"
        对象被引用,例如b = a
        对象被作为参数,传入到一个函数中,例如fun(a)
        对象作为一个元素,存储在容器中,例如data_list=[a,b]
    引用计数-1的情况:
        对象的别名被显式销毁,例如del a
        对象的别名被赋予新的对象,例如a = 24
        一个对象离开它的作用域,例如func函数执行完毕时,func函数中的局部变量(全局变量不会)
        对象所在的容器被销毁,或从容器中删除对象
    """
    # 2 分代回收
    """
    既然已经有引用计数了,那么为什么还要提出分代回收呢?原因就是引用计数没办法解决“循环引用”的情况。
    a = ["yuan", ]   # 语句1
    b = ["rain", ]    # 语句2
    a.append(b)          # 语句3
    b.append(a)          # 语句4
    # 此时对象的值:a = ["yuan", b]   b = ["rain", a]
    del a                # 语句5
    del b                # 语句6
    # 执行完语句5和语句6是希望同时删除掉a对象和b对象
    
    在执行"del a"语句之后,只是删除了对象的引用,也就是此时a变量这个名字被删除,也就是此时对象["yuan",b]的引用计数减1;执行"del b"语句也是同样的情况。但是,此时,由于显式指向它们的变量已经不存在了,所以也没办法删除了,就会导致它们一直存在于内存空间中。 这就是循环引用出现的问题。 此时,单靠引用计数没办法解决问题。所以便提出了分代回收
    
    注意:在分代回收中,如果某对象的引用计数为0,那么它所占的内存空间同样也会被python解释器回收。
    
    a、此时在python中每创建一个对象,那么就会把对象添加到一个特殊的“链表”中,这个链表称为"零代链表"。每当创建一个新的对象,那么就会将其添加到零代链表中。当这个"零代链表"中的对象个数达到某一个指定的阀值的时候,python解释器就会对这个"零代链表"进行一次“扫描操作”。这个“扫描操作”所做的工作是查找链表中是否存在循环引用的对象,如果在扫描过程中,发现有互相引用的对象,那么会让这些对象的引用计数都减少1。此时,如果某些对象引用计数变成0,那么就会被python解释器回收其所占用的内存空间;如果对象的引用计数仍然不为0,那么会把此时存活的对象迁移到“一代链表”中。
    
    b、同样,python解释器也会在一定的情况下,也扫描“一代链表”,判断其中是否存在互相引用的对象。如果存在,那么同样也是让这些对象的引用计数都减少1。此时,如果某些对象引用计数变成0,那么就会被python解释器回收其所占用的内存空间;如果对象的引用计数仍然不为0,那么会把此时存活的对象迁移到“二代链表”中。
    
    c、同样,python解释器也会在一定的情况下,也会扫描"二代链表",判断其中是否存在互相引用的对象。如果存在,那么同样也是让这些对象的引用计数都减少1。此时,如果某些对象引用计数变成0,那么就会被python解释器回收其所占用的内存空间;如果对象的引用计数仍然不为0,那么会把此时存活的对象迁移到一个新的特殊的内存空间。此时重新进行"零代链表 -> 一代链表 -> 二代链表"的循环。
    
    这就是python的分代回收机制。
    """
    
    # 标记清除
    """
    那么既然已经有分代回收了,那么为什么又要提出标记-清除呢?
    原因就是分代回收没办法解决“误删”的情况。
    a = ["yuan", ]   # 语句1
    b = ["rain", ]    # 语句2
    a.append(b)          # 语句3  
    b.append(a)          # 语句4  
    # 此时对象的值:a = ["yuan", b]   b = ["rain", a].   ["yuan", b] 、["rain", a]的引用计数都为2
    del a                # 语句5
    # 此时["yuan", b]的引用计数为1, ["rain", a]的引用计数为2
    # 执行完语句5只希望删除a对象,保留b对象
    
    如果按照分代回收的方式来处理上述语句。那么,python解释器在执行完语句5之后。在一定的情况下进行查找循环引用对象的时候,会发现此时["rain", a]对象和["yuan", b]对象存在互相引用的情况。所以此时就会让这两个对象的引用计数减1。此时,["yuan", b]对象的引用计数为0,所以["yuan", b]对象被真正删除,但是其实此时["rain", a]对象中是有一个变量引用原来的["yuan", b]对象的。如果["yuan", b]对象被真正删除的话,那么此时时["rain", a]对象中的a变量就没有用了,就没有办法访问了。但是其实我们是希望它有用的,所以这个时候就出现“误删”的情况了。所以此时就需要结合“标记-清除”来解决问题了。
    
    标记-清除:
    此时同样是检测链表中的相互引用的对象,然后让它们的引用计数减1之后;
    但是此时会将所有的对象分为两组:死亡组(death_group)和存活组(survival_group),把引用计数为0的对象添加进死亡组,其它的对象添加进存活组;
    此时会对存活组的对象进行分析,只要对象存活,那么其内部的对象当然也必须存活。如果发现内部对象死亡,那么就会想方设法让其活过来,通过这样子就能保证不会删错对象了。
    
    题目的重新分析:
      在检查死亡组的时候,会发现["rain", a]对象中的a所指向的对象存在于死亡组中,所以就会想方设法让其复活,此时就能够保证["rain", a]对象中所有的对象都是存活的。
    
    """
    
  35. Python的内存管理机制

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

  37. python2与python3的区别

  38. 聊聊你对python的理解?

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

    1
    2
    3
    4
    5
    6
    
    1. 二元运算符和逗号后面使用空格,但是括号里侧不加空格,如:a = f(1, 2) + g(3, 4)。
    2. 每一级缩进使用4个空格。
    3. 顶层函数和类的定义,前后用两个空行隔开。类里的方法定义用一个空行隔开。
    4. 导入格式:每个导入独占一行,导入放在文件顶部,位于模块注释和文档字符串之后,模块全局变量和常量之前。导入应该按照从最通用到最不通用的顺序分组(标准库 -> 第三方库 -> 自定义库)
    5. 注释块通常应用在代码前,并和代码有同样的缩进。每行以 ‘# ' 开头, 而且#后面有单个空格。
    6. 包和模块名应该简短,全部用小写字母, 多字母之间可以使用单下划线连接。类名遵循驼峰命名
    

第二篇、并发技术

  1. 简述 进程、线程、协程的区别 以及应用场景?
  2. 进程之间如何进行通信?
  3. 聊聊什么是GIL锁
  4. 什么是生产者消费者模型
  5. asynio是什么?

第三篇、网络编程

  1. 简述 OSI 七层协议。

  2. 简述 TCP 和 UDP 的区别以及优缺点?

  3. 简述三次握手和四次挥手的流程

  4. 说一下什么是TCP 的 2MSL?

  5. 为什么客户端在 TIME-WAIT 状态必须等待 2MSL 的时间?

  6. 什么是域名解析?

  7. 什么是cdn?

  8. 什么是arp协议?

  9. 什么是局域网和广域网?

  10. 图片管理为什么使用FastDFS?为什么不用云端?它的好处是什么?

  11. IO多路复用的作用?

  12. select、poll、epoll 模型的区别?

  13. iptables知识考察, 根据要求写出防火墙规则?

  14. 业务服务器192.168.1.2访问192.168.1.3数据接口, 无法正常返回数据, 请根据以上信息写出排查思路。

  15. 什么是twisted框架?

  16. 路由器和交换机的区别?

  17. 如何修改本地hosts文件?

第四篇、数据库

  1. MySQL常见数据库引擎及区别?

  2. mysql下面那些查询不会使用索引,between, like “c%” , not in, not exists, !=, <, <=, =, >, >=,in

  3. 什么是事务

  4. MySQL索引种类

  5. 对sql的优化有哪些

  6. MySQL中having的作用

  7. 数据库中有一条语句执行速度非常慢,请问如何优化

  8. 简要说说MySQL中的主从复制

  9. 简述数据库读写分离?

  10. 简述悲观锁与乐观锁

  11. 简述sql注入的攻击原理及如何在代码层面防止sql注入?

  12. 什么是索引合并?

  13. 什么是覆盖索引?

  14. 什么是MySQL慢日志?

  15. 简述MySQL的存储过程和触发器

  16. 开发过程中对于数据库设计的经验

  17. 你了解那些数据库优化方案?

  18. 举例说明下Redis五种数据类型及应用场景

  19. redis和memcached的区别?

  20. Redis 和 MongoDB 的优缺点

  21. MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?

  22. 如何基于redis实现发布和订阅?以及发布订阅和消息队列列的区别?

  23. 什么是哨兵模式以及哨兵模式的作用

  24. 在Redis中,什么时候需要用到pipeline?

  25. Redis 集群实现?

  26. redis中数据库默认是多少个db

  27. redis是单进程还是单线程?

  28. redis的雪崩和击穿

  29. Redis 的使用场景有哪些?

  30. redis宕机了怎么办,如果是项目上线的宕机呢?

  31. 通过底层原理聊聊Redis为什么比MySQL快?

  32. redis如何做持久化

  33. redis中的watch的命令的作用?

  34. MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?

第五篇、Web开发

  1. 常见的状态码

  2. 请简述http缓存机制

  3. 说说 HTTP 和 HTTPS 区别?

  4. get请求和post请求的区别

  5. Django、flask、tornado框架的比较?

  6. Django的生命请求周期

  7. 对 MVC,MTV的理解?

  8. 简述Django中间件以及应用场景

  9. cookie与sessiion

  10. 什么 csrf 攻击原理,django中csrf的处理机制?

  11. Django的查询集(queryset)的特性

  12. Django的orm中only和defer的区别?

  13. selectrelated和prefetchrelated的区别?

  14. 解释orm中 db first 和 code first的含义?

  15. Django中如何根据数据库表生成model类?

  16. django的contenttype组件的作用

  17. 简述django FBV和CBV?

  18. django下的(內建的)缓存机制

  19. Django 如何提升性能(高并发)

  20. 跨域问题产生的原理和解决思路是?

  21. Django中如何实现websocket?

  22. Flask框架依赖组件?

  23. Flask蓝图的作用?

  24. 简述Flask上下文管理流程?

  25. 为什么要Flask把Local对象中的的值stack 维护成一个列表?

  26. Flask中多app应用如何编写?

  27. SQLAlchemy如何执行原生SQL?

  28. 简述一下DRF以及包含的常用组件

  29. 聊聊RPC应用

  30. 简述websocket协议及实现原理

  31. Django线上部署

  • Django 本身提供了 runserver,为什么不能用来部署?

  • 什么是wsgi? 什么是uwsgi?

  • 谈一下你对 uWSGI 和 nginx 的理解?

  • django常见的线上部署方式

  • 什么是keepalived?

    第六篇、项目开发

  1. 公司线上和开发环境使用的什么系统?
  2. 你的项目基于什么平台开发的?
  3. 介绍下项目中表设计
  4. 你的项目中有哪些功能模块?
  5. 后台开发人员有几个?如何分工?
  6. 保利威这个服务是部署在公网还是内网?
  7. 秒杀系统开发中的并发处理方案
  8. token和jwt的区别
  9. 不同的服务器怎么共享session
  10. 你们部署服务器是几台,并发量是多大;
  11. celery的底层实现原理,比单独线程完成耗时任务的优点
  12. 你们的服务器数量和类型
  13. 开发过程中消息队列的应用
  14. 项目的并发量,对于高并发的处理机制
  15. 分布式架构的应用
  16. 验证码过期时间怎么设置?
  17. 如何识别活跃用户
  18. 如何实现商品推荐
  19. ElesticSearch的应用
  20. 待支付功能如何实现
  21. 退款的逻辑如何完成
  22. 什么是页面静态化,为什么使用页面静态化而不是缓存