基础面试

第一部分 Python基础篇(80题)
1.    为什么学习Python?
        我觉得python作为一个解释型语言,开发效率和排错效率都比较高,
        其次,第三方库丰富,移植性非常好,绝大多数程序不做任何修改就可以在所有主流的计算机平台上运行
        最后,python作为一个胶水语言应用领域广泛。
            1.web开发,django,flask
            2.人工智能,科学运行
            3.金融量化分析
        
2.    通过什么途径学习的Python?
        大学自学,网络视频,cnblog,51cto
    
3.    Python和Java、PHP、C、C#、C++等其他语言的对比?
        python语言:是一种面向对象,语法简洁清晰,具有丰富而强大的库,常被称为胶水语言,他能轻松的把其他语言制作成各种模块轻松的使用。
        Java:
        php:web网站开发,入门上手很容易
        c:嵌入式或低层开发
        c++:桌面软件以及游戏开发
        C#:
    
4.    简述解释型和编译型编程语言?
    编译型:先把程序编译成机器码,然后执行
        1.执行速度快
        2.开发效率低,排错慢,移植性差(不同操作系统,低层机器指令不同)
        3.每次修改源码,都要重新编译
    解释型:运行时用解释器把程序一行一行解释执行
        1.排错快,开发效率高,移植性好
        2.执行效率较低
        3.代码是明文的
    
5.    Python解释器种类以及特点?
        CPython:c语言开发的使用最为广泛
        IPython:基于cpython之上的一个交互式解释器
        PyPy:对Python代码进行动态编译,所以执行效率高
        JPython:运行在Java解释器上的,直接把python代码编译成Java字节码执行
        IronPython:IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器

6.    位和字节的关系?
        位:常说的bit,计算机中的最小单位,就是0和1
        字节:byte,存储空间的基本计量单位,1Byte = 8bit
    
7.    b、B、KB、MB、GB 的关系?
        1Byte = 8bit
        1KB = 1024B
        1MB = 1024KB
        1GB = 1024MB
    
8.    请至少列举5个 PEP8 规范(越多越好)。
        1.总是在运算符两次加空格
        2.在class和一级函数上用两个空行,类内的函数使用一个空行
        3.注释的时候#前空两空格,后空一空格
        4.代码最后需要空一行
        5.函数间空两行
        6.逗号后面空一格
        7.import导入顺序:标准库,第三方库,本地库
    
9.    通过代码实现如下转换:
    二进制转换成十进制:v = “0b1111011”
        int('0b111011', base=2    # 123
    十进制转换成二进制:v = 18
        bin(18)      # '0b10010'
    八进制转换成十进制:v = “011”
        int('011', base=8)  # 9
    十进制转换成八进制:v = 30
        oct(30)  # '0o36'
    十六进制转换成十进制:v = “0x12”
        bin('0x12', base=16)  # 18
    十进制转换成十六进制:v = 87
        hex(87)   # 0x57
    
10.    请编写一个函数实现将IP地址转换成一个整数。
如 10.3.9.12 转换规则为:
        10            00001010
         3            00000011
         9            00001001
        12            00001100
再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?
    ip = '10.3.9.12'
    num_list = ip.split('.')
    bin_str = ""
    for num in num_list:
        bin_str += bin(int(num))[2:].zfill(8)
    print(bin_str)  # 00001010000000110000100100001100
    print(int(bin_str, base=2))  # 167971084

11.    python递归的最大层数?
    900多,1000左右,998
    import sys
    sys.setrecursionlimit(10000) #设置递归深度
    
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     # False
    
13.    ascii、unicode、utf-8、gbk 区别?
    ascii:数字,英文,特殊字符,一共8位,最左位是扩展位,扩展位使用了后叫eascii
    unicode:万国码,所有国家的语言都包含在,32位表示一个字符,资源浪费,占用空间多
    utf-8:最少用8位表示一个字符,英文占8位,欧文占16位,亚洲占24位
    GBK:国标码,英文8位,中文16位
    在计算机内部统一使用的是Unicode码,当需要保存到硬盘或者传输的时候,就转换为UTF-8;从文件中
        读取的时候,就转换为Unicode字符到内存中。
    
14.    字节码和机器码的区别?
    字节码:是编译后生成的一种中间状态的二进制文件,
    机器码:机器语言指令,是电脑cpu可以直接解读的,可以直接在计算机上执行,执行速度最快

15.    三元运算规则以及应用场景?
    三元运算符:是对简单条件语句的简写
    print(1 if 3>4 else 0)
    适用于简单的条件语句
    
16.    列举 Python2和Python3的区别?
    python2:源码混乱,重复代码较多
    python3: 源码规范,优美清晰简单
    
    python3.0  2008年
    python2.7  2010年(最后的2版本)
    print:
        python2:print 'xx' 或者 print('xx')
        python3: print('xx')
    编码:
        python2:默认是ascii
        python3: 默认是utf-8
    input:
        python2: raw_input()
        python3: input()
    继承:
        python2: 经典类,继承了object就变为新式类----深度优先
        python3: 都是新式类,----广度优先
    range:
        python2:中有两种方式,range()生成的是一个列表,xrange()生成的是一个可迭代对象
        python3:range生成的是一个可迭代对象
    long:
        python2:中有长整型long
        python3:中只有int
    字典的键:
        python2:中用has_key()的方法来判读字段是否包含指定的键
        python3:中使用in来判断
        
17.    用一行代码实现数值交换:
      a = 1
      b = 2
      
      a,b = b,a
      
18.    Python3和Python2中 int 和 long的区别?
    在python2中有long数据类型,python2.2中如果int发生溢出,则自动转为long
    在python3中只有int类型,没有long类型了

19.    xrange和range的区别?
    python2:中有两种方式,range()生成的是一个列表,xrange()生成的是一个可迭代对象
    python3:range生成的是一个可迭代对象
    
20.    文件操作时:xreadlines和readlines的区别?
    xreadlines(): 返回一个生成器,来循环操作文件的每一行。循环使用时和readlines基本一样,但是直接打印就不同,xreadlines是python2中的
    
    readlines():读取文件所有内容,按行为单位放到一个列表中,返回list类型。
    readline()读取一行内容,放到一个字符串变量,返回str类型。
    read():全部读取出来
    read(x):在rb模式下是按照字节去读取
    
21.    列举布尔值为False的常见值?
    空字符串 ,0 , 空字典, 空列表
    bool('')
    bool(0)
    bool({})
    bool([])
    bool(())
    
22.    字符串、列表、元组、字典每个常用的5个方法?
    str:
        s.capitalize()    # 首字母大写,其他字母变小写
        s.upper()        # 全部大写,lower全部小写
        s.swapcase()    # 大小写翻转
        s.title()        # 每个单词首字母大写(非字母隔开的),其他字母变小写
        s.startswith()    # 判断以什么开头,endswith以什么结尾
        s.strip()        # 去掉首位的空格换行tab,lstrip,rstrip
        s.find()         # 查找字符的索引,找不到返回-1
        s.index()        # 查找字符的索引,找不到就报错
        s.count()        # 计数
        s.replace()        # 替换,默认全部替换,可以设置替换次数
        s.split()        # 分割,从左向右分割,返回列表,rsplit
        s.isalnum()        # 是否由字母数字组成,不包括字符
        s.isalpha()        # 是否只由字母组成
        s.isdigit()        # 是否由数字组成
    list:有序的,有索引值,可以切片,方便使用
        lis.append()    # 在列表最后追加
        lis.insert()    # 插入
        lis.extend()    # 迭代添加,只要是可迭代对象,都是迭代添加
        lis.pop()        # 按照索引删除,不填写索引默认删除最后一个,删除什么返回什么
        lis.remove()    # 按照元素去删除,只能删除一个
        lis.clear()        # 清空列表,list还在内存中,只是清空元素
        del lis            # 删除列表,后就不存在内存中了,可以按照切片删除
        li.sort()        # 排序,默认从小到大排序,reverse=True,从大到小排序,也可以字符串排序(全部都是)
        li.reverse()    # 翻转列表
        li.index()        # 通过元素找索引
    tuple:只读,可以切片,查看,不可以改变(儿子不可改,孙子可以改)
        只有三种方法:
            tu.count()    # 计数
            len(tu)        # 长度
            tu.index()    # 通过元素找索引
    dict:
        dic['key'] = 'value'#无则添加,有则覆盖
        dic.setdefault('key','value') # 无则添加,有则不变
        dic.pop('key')    # 有返回值(value),删除什么返回什么,删除没有的key则报错,dic.pop('key',None)
        dic.popitem()    # 随机删除,返回(key,value)元组键值对
        dic.clear()        # 清空字典
        del dic            # 直接删除
        dic.get('key')    # 找不到返回None
        dic.keys()        # keys,在list中
        dic.values()    # vlaues,在list中
        dic.items()        # 键值对
        
23.    lambda表达式格式以及应用场景?
    简单的说lambda表达式就是一个简单的函数,也就是指匿名函数,为了解决功能简单而写的一句话函数
    lambda x:x**2
    
24.    pass的作用?
    pass是空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句
    
25.    *arg和**kwarg作用
    这是一种特殊的语法,在函数定义中使用*args和kwargs传递可变长参数.
    args的作用是接收所有未被对应的位置参数, 将其聚合成元组
    kwargs的作用是接收所有未被对应的关键字参数,放在字典中
    
    在函数调用的时候:*的作用是打散拆开可迭代对象的元素,形成关键字参数传参
    在函数定义的时候:*的作用是聚合成元组
    
    在函数调用的时候:**的作用是打散拆开可迭代对象的元素,形成键值对的方式传参
    在函数定义的时候:**的作用是聚合成字典
    
26.    is和==的区别
    is:比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同,比较id是否相同
    ==:比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。默认会调用对象的 __eq__()方法

27.    简述Python的深浅拷贝以及应用场景?
    python采用基于值的内存管理模式,赋值语句的执行过程是:首先把等号右边的表达式计算出来,然后存在内存中,最后
    创建变量指向这个内存地址
    python中的变量并不是直接存储值,而是存储值的内存地址
    
    浅copy:第一层创建的是新的内存地址,从第二层开始都是指向的同一个内存地址,所以对于第二层以及更深层来说保持
    一致性,切片输入浅copy
        1.    li2 = li.copy()
        2.     import copy
            li2 = copy.copy(li)
        两种表示方法而已,都是浅copy
    深copy:两个是完全独立的,改变任意一个的任何元素(无论多少层),另一个绝对不会变化
        import copy
        li2 = dopy.deepcopy(li)
        
28.    Python垃圾回收机制?
    python 中的垃圾回收以引用计数为主,分代回收为辅。
    引用计数:预编译中做计数
        a = 1;a+b # 这里引用了a一次,所以a的引用计数就为1
        一旦没有引用,内存就直接释放了
        优点:简单,实时:一旦没有引用了,内存就直接释放
        缺点:维护引用计数:消耗资源
              循环引入问题:占用的内存无法被回收,导致内存泄漏(动态分配的内存由于某种原因无法被释放)
              
    分代回收:空间换时间
        python将内存分为三代,他们对应三个链表
        每个容器可以存放700个变量,数据一创建的时候就放到第0代(生命周期最短的链表中),
        当超过700个变量额时候,就会把第0代中可以回收的回收掉,不能回收的放到第1代中,以此类推。
        
29.    Python的可变类型和不可变类型?
    这里的可变与不可变,是指内存中的那块内容(value)是否可以被改变
    可变的数据类型:list,dict,set
    不可变的数据类型:int,str,bool,tuple
    
    i = 5
    int类型为例:实际上 i += 1 并不是真的在原有的int对象上+1,而是重新创建一个value为6的int对象,i引用自这个新的对象。
    
30.    求结果:
    v = dict.fromkeys(['k1', 'k2'], [])
    # 迭代添加使用的是同一个列表,所有k1,k2的value都是空列表,指向相同的内存地址
    v['k1'].append(666)
    print(id(v['k1']), id(v['k2']))  # 42482120 42482120
    print(v)  # {'k1': [666], 'k2': [666]}
    # 将k1设置为777,则k1指向777的内存地址,失去了list的属性,k2依旧保留
    v['k1'] = 777  
    print(id(v['k1']), id(v['k2']))  # 42066960 42482120
    print(v)  # {'k1': 777, 'k2': [666]}
 
31.    求结果:
    def num():
    return [lambda x:i*x for i in range(4)]

    for i in [m(2) for m in num()]:
        print(i)  # 4个6

    for i in (m(2) for m in num()):
        print(i)  # 4个6
        
32.    列举常见的内置函数?
    hash()    # 获取一个可hash对象的哈希值
    id()    # 获取对象的内存地址
    callable()# 检查一个对象是否可以调用
    dir()    # 查看对象的内置属性
    int(x,base=y)
    bin()    # 十进制转成二进制
    oct()    # 十进制转成八进制
    hex()    # 十进制转成十六进制
    abs()    # 返回数字的绝对值
    divmod(a,b)# (a//b,a%b)  取整,取余
    round(7/3,2)# 保留浮点数的小数位数,默认保留为整数
    pow(2,3)    # 2**3
    sum([1,2,3])#对可迭代对象求和,可设置初始值
    min()    # 返回可迭代对象的最小值,可以设置key规则
    max()    # 同上
    reversed()    # 将一个序列翻转,成迭代器,
    ord()    # 通过字符找ascii位置
    chr()    # 通过ascii位置,返回字符
    ascii()    # 判断是不是ascii码,不是返回\u……
    repr()    # 返回对象的string形式
    sorted()# 对所有的可迭代对象进行排序,reverse=True倒序
    all()    # 可迭代对象中全部是True才是True
    any()    # 可迭代对象中有一个为True就是True
    zip()    # 将多个可迭代对象作为参数,一一对应打包成一个一个元组,返回迭代器,元组长度和最小的一样
    filter()# 只能过滤,不能加工,返回一个迭代器,通过一个函数过滤
    map()    # 根据提供的函数做序列的映射,加工,通过一个函数,加工
    
33.    filter、map、reduce的作用?
    1.filter(func,iterable),通过func过滤iterable
    2.map(func,iterable),通过函数做iterable的加工映射
    3.reduce(func,iterable),是python2的内置函数,在python3中被移到functools模块中了
        首先把iterable中的前两个元素传给函数,函数加工后,然后把结果和第三个元素作为参数
        传递给函数,依次类推。可以设置传递初始值,那么就是初始值和第一个元素,依次类推

34.    一行代码实现9*9乘法表
    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)))
    
35.    如何安装第三方模块?以及用过哪些第三方模块?
    1.在pycharm中直接安装,或者用pip安装
    2.使用过:re,os,sys,time,datetime,json,hashlib,random,bs4,uuid,pymsql,pillow,xlwt
    
36.    至少列举8个常用模块都有那些?
    re:正则
    os:当前操作系统相关
    sys:python解释器相关
    time:
    datetime:
    json:序列化与反序列化
    hashlib:加密相关
    random:随机数据
    uuid:随机uuid
    
37.    re的match和search区别?
    search:找到一个就返回,返回一个结果对象,使用group()取值,找不到返回None
    match:正则表达式前面加了一个^,找到一个就返回,返回一个结果对象,使用group()取值,找不到返回None

38.    什么是正则的贪婪匹配?
    贪婪匹配:在满足匹配时,匹配尽可能长的字符串
    默认是贪婪匹配:在量词的后面加一个?,就是非贪婪匹配了
    
39.    求结果:
    a. [ i % 2 for i in range(10) ]
        列表推导式,返回的是一个[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
    b. ( i % 2 for i in range(10) )
        生成器推导式,返回的是一个生成器对象,使用__next__取值
        
40.    求结果:
    a. 1 or 2         # 1
    b. 1 and 2         # 2
    c. 1 < (2==2)     # False
    d. 1 < 2 == 2    # True    1<2 and 2 = 2

41.    def func(a,b=[]) 这种写法有什么坑?
    b=[] 在传参的时候将一个列表指向b,如果在函数中更改了b的值,其会影响全局变量的值
    
42.    如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?
    print([i for i in a.split(',')])
    
43.    如何实现[‘1’,’2’,’3’]变成[1,2,3] ?
    print([int(i) for i in a.split(',')])
    
44.    比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?
    a是一个列表,里面有元素1,2,3
    b是一个列表,里面有元素1,2,3
    c是一个列表,里面有元素(1,),(2,),(3,)
    
45.    如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?
    print([i**2 for i in range(1,11)])
    
    map(lambda x:x**2,[i for i in range(1,11)])
    
46.    一行代码实现删除列表中重复的值 ?
    li = [1,2,3,4,5,3,2,1]
    print(list(set(li)))  # [1, 2, 3, 4, 5]
    
47.    如何在函数中设置一个全局变量 ?
    global name   # 在局部作用域中声明一个全局变量
    
48.    logging模块的作用?以及应用场景?
    作用:
        1.分析,了解,系统的运行情况,如果log足够丰富,也可以分析用户的操作,喜好等信息
        2.通过log级别,让维护人员更准确的分析定位故障
        3.重要的数据库操作的凭证
    应用场景:
        1.在用户登录,退出等需要记录
        2.在做相关操作的时候需要记录
        3.在数据库修改个时候需要记录
        4.在出现程序bug,报错的时候需要记录
        

50.    常用字符串格式化哪几种?
    print("%s,%s" %(a,b))
    print("{},{}".format(a,b)
    print(f'{a},{b}')  #python3.6
    s = '我叫{},今年{},爱好{}'.format('MT',18,'母牛') #{}相当于占字符
    print(s) #我叫MT,今年18,爱好母牛
    第二种用法:
    s = '我叫{0},今年{1},爱好{2},我依然叫{0}'\
        .format('MT',18,'母牛') #{}相当于占字符
    print(s) #我叫MT,今年18,爱好母牛,我依然叫MT
    一行太长可以用\ 来换行操作。
    第三种  键值对形式
    s = '我叫{name},今年{age},爱好{hobby}'.format(age=18, name='MT', hobby='看电影')
    
51.    简述 生成器、迭代器、可迭代对象 以及应用场景?
    生成器:生成器本质上就是迭代器,一个特殊的迭代器
        通过列表推导式,我们可以得到一个列表,但是如果列表元素巨大,我们就可以
        使用生成器,使用yield返回值,每次调用yield会暂停,
    迭代器:内部不仅含有__iter__还有__next__方法的
        数列的数据规模很大的时候,
    可迭代对象:内部含有__iter__方法的
    
    
52.    用Python实现一个二分查找的函数。
    # 递归版本
    def bin_search(data, val, low, high):
        if low <= high:
            mid = (low + high) //2
            if data[mid] == val:
                return mid
            elif data[mid] > val:
                return bin_search(data, val, low, mid-1)
            else:
                return bin_search(data, val, mid+1, high)
        else:
            return None
    
    # 循环版本
    def bin_search(li, val):
        low = 0
        high = len(li) - 1
        while low <= high:
            mid = (high + low) //2
            if li[mid] == val:
                return mid
            elif li[mid] < val:
                low = mid + 1
            else:
                high = mid - 1
        return None
        
53.    谈谈你对闭包的理解?
    闭包必须满足三个条件:
        1.必须是一个嵌套函数
        2.必须返回嵌套函数
        3.嵌套函数必须引用一个外部非全局的局部变量
    在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。
    这样就构成了一个闭包。
    def outer(a):   # outer是外部函数 a和b都是外函数的临时变量
        b = 10
        def inner(): # inner是内函数
            print(a+b) #在内函数中 用到了外函数的临时变量
        return inner # 外函数的返回值是内函数的引用
    
    demo = outer(5) # 调用外函数传入参数5
    # 此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
    # 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
    demo() # demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
    
54.    os和sys模块的作用?
    os:使用操作系统相关的
        os.getcwd()        # 获取当前文件所在的路径
        os.mkdir('dirname')        # 在当前目录中,产生一个新文件夹
        os.makedirs('dirname/son_dirname')    #在当前目录中,创建多级目录
        os.stat(file)    # 查看文件信息
        os.remove(path)    # 删除一个文件
        os.rmdir(path)        # 删除一个目录,要求path必须是个空目录
        os.removedirs(path)    # 删除多级目录,都为空
        os.listdir('dir')    # 将dir下的文件,文件夹写在list中
        os.system('cmd命令')# 执行cmd命令,有乱码、
        print(os.getppid())    # 获取当亲运行程序的parent pid
        print(os.getpid())   #获取当前运行的程序的进程PID
        print(os.popen('dir').read())  # 执行cmd命令,没有乱码
        print(os.path.abspath('1.py'))  # 绝对路径
        print(os.path.dirname(os.path.abspath('1.py')))  # 路径dirname
        print(os.path.split(os.path.abspath('1.py'))) # (dirname,filename)
        print(os.path.exists('1.py')) # 判断一个文件或目录是否存在
        print(os.path.isfile('1.py')) # 判断是不是文件
        print(os.path.isdir('1.py'))  # 判断是不是目录
        print(os.path.join('e:\\python\project', 'test.py'))  # 拼接路径和文件
        print(os.path.getatime('1.py')) # 访问时间,timestamp
        print(os.path.getmtime('1.py')) # 修改时间,timestamp
        print(os.path.getsize('1.py'))  # 大小,字节
    sys:与解释器进行交互
        print(sys.version) #查看python解释器版本
        print(sys.path)  # 返回模块的搜索路径,初始化使用的是PYTHONPAHT环境变量的值
        print(sys.argv)  # 返回list,第一个元素是程序本身路径,后续还有其他参数
        # 在脚本程序执行的时候,可以输入用户名和密码同时进行登录操作
        # eg:  有一个脚本login.py
        #      执行的时候:python login.py username password
        #      取值:sys.argv[0] 是程序本身路径
        #      sys.argv[1] 是username 。。。。

        # 如果需要更好的控制输出,而print不能满足需求,sys.stdout,sys.stdin,sys.stderr就是你需要的。
        sys.stdout  #标准输出

        sys.stdin #标准输入

        sys.stderr # 错误输出

55.    如何生成一个随机数?
    print(random.random())    # (0,1) 随机小数
    print(random.uniform(1,3)) # (1,3) 随机小数
    print(random.randint(1,100) # [1,100] 整数
    print(random.randrange(1,100)) # [1,100) 整数
    print(random.choice([1,2,3,4,6,3])) # 随机返回列表元素
    print(random.choice([1,2,3,4,6,3],2)) # 随机返回列表两个元素
    print(random.sample([1,2,3,45,[1,2,],3])) # 随机取出两个元素
    random.shuffle(lis)    # 打乱顺序
    随机验证码:0-9/48-57, A-Z/65-90, a-z/97-122
        import random
        for i in range(4):
        lis = random.choice([[48,58],[65,91],[97,123]])
        print(chr(random.randrange(lis[0],lis[1])),end="")
    
56.    如何使用python删除一个文件?
    import os
    my_file = 'd:/text.txt'
    if os.path.exists(my_file):
        os.remove(my_file)
    else:
        print('no such file:%s' %my_file)
        
57.    谈谈你对面向对象的理解?
    在Python中一切皆对象:通过面向对象的方式,将现实世界的事物抽象成对象,关系抽象成类。帮助
    人民对现实世界的抽象与数学建模
        所谓的面向对象,就是将程序模块化,对象化,把具体的事物的特性属性
    面向对象的三大特征:
        继承:
            继承的概念:一个类继承另一个类
            目的:实现代码的复用
            结果:继承后子类拥有了父类的属性和方法,子类可以写自己特有的属性和方法,目的是实现扩展
                  子类也可以复写父类的方法,重写
        封装:
            概念:数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系
            好处:1.实现了专业的分工。将能实现某一特定功能的代码封装成一个独立的实体后,
                    各程序员可以在需要的时候调用
                  2.隐藏信息,实现细节。通过控制访问权限可以将可以将不想让客户端程序员看到的信息隐藏起来,
                    如某客户的银行的密码需要保密,只能对该客户开发权限。
        多态:
            概念:相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。
    
    面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以
    了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个
    解决问题的步骤中的行为。

58.    Python面向对象中的继承有什么特点?
    1.单继承,多继承
    
59.    面向对象深度优先和广度优先是什么?
    python3中的类,默认继承object类,继承了object的类就是新式类:在多继承中用广度优先查找
    python2中的类:默认是经典类(多继承,深度优先查找),继承了object的类就变为新式类了
    深度优先和广度优先是一种算法:
        深度优先:在多继承中查找,一条路走到底,没有则换路
        广度优先:在多继承中查找,从左向右,如果一个节点在后续中可以被遍历到,那么就换路继续

60.    面向对象中super的作用?
    1.单继承中:在子类中调用父类的方法,super(FooChild,self).fun(data)
    2.多继承:就是根据子节点所在图的mro顺序(这里super不是找父类用的)寻找下一个类
    
61.    是否使用过functools中的函数?其作用是什么?
    partial:偏函数,为函数进行默认传参
        from functools import partial
        def func(a1,a2):
            print(a1+a2)
        new_func = partial(func,8) #a1=8
        new_func(3) #a2=3,11
    reduce:将iterable的前两个值拿出来进行函数加工
    wraps:保留函数原始信息

62.    列举面向对象中带双下划线的特殊方法,如:__new__、__init__
    __new__(cls)是在新式类中新出现的方法,它的作用是在构造方法创建实例之前,并且需要传递一个参数cls,
        cls表示需要实例化的类(当前正在实例化的类),这个参数在实例化的时候由Python解释器自动提供。
        必须有返回值,放回当前对象的实例
        
    __init__():方法是类实例创建之后调用, 对当前对象的实例的一些初始化, 没有返回值
    
    __str__():只能返回一个字符串,并且只有一个参数,print(类的对象)的时候,就调用这个方法
    
    __repr__():需要使用__str__的时候找不到,就找__repr__,所有__repr__是__str__备胎
    
        str(obj)的结果依赖__str__
        print(obj)的结果依赖__str__
        %s的结果依赖__str__
        repr的结果依赖__repr__
        %r的结果依赖__repr__
    
    __call__():对象通过提供一个__call__()方法,可以模拟函数的调用,如果一个对象提供了__call__方法。
    
    __eq__():判断==的时候自动调用的内置方法
        class A:pass
        a = A()
        b = A()
        print(a) #不同的内存地址
        print(b) #不同的内存地址
        print(a == b) #False
        print("__eq__" in object.__dict__) #True  使用object提供的内置__eq__方法

        # 自定义内置__eq__
        class A:
        def __init__(self,name):
            self.name = name

        def __eq__(self, other):
            if self.__dict__ == other.__dict__:
                return True
            else:
                return False
        a = A('alex')
        b = A('alex')
        print(a.__dict__)  # {'name': 'alex'}
        print(b.__dict__)  # {'name': 'alex'}
        print(id(a))  # 31555712
        print(id(b))  # 31555656
        print(a == b)  # True
        # 如果没有__eq__那么通过父类的__eq__判断的是对象的内存地址是否相等
    
    __del__():当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
              对于开发者来说很少会直接销毁对象(如果需要,应该使用del关键字销毁)
              Python的内存管理机制能够很好的胜任这份工作。也就是说,不管是手动调用del还是由python
              自动回收都会触发__del__方法执行
              当程序运行完的时候,python解释器会自动进行收尾工作,回收分配的内存空间
              
    __len__():只要一个类必须实现了一个__len__方法,才能使用len函数
        class A:
            def __init__(self,name,age,sex,cls):
                self.name = name
                self.age = age
                self.sex = sex
                self.cls = cls
            def __len__(self):
                return len(self.__dict__)
        #有一个内置函数和内置方法len()是唯一对应的关系
        a = A("alex",81,'不详',2)
        print(a.__dict__) # {'name': 'alex', 'age': 81, 'sex': '不详', 'cls': 2}
        print(len(a)) #4
        print(a.__len__()) #4
    
    __format__(self,format_spec):格式化输出
        class A:
            def __init__(self,name,school,addr):
                self.name = name
                self.school = school
                self.addr = addr
            def __format__(self,format_spec):
                return format_spec.format(obj=self)
        a = A("taibai","baidu","上地")
        format_spec = '{obj.name}-{obj.school}-{obj.addr}'
        print(format(a,format_spec))  #taibai-baidu-上地
        
        
63.    如何判断是函数还是方法?
    from types import MethodType,FunctionType
    def check(arg):
        if isinstance(arg,MethodType):
            print('这是一个方法')
        elif isinstance(arg,FunctionType):
            print("这是一个函数")
        else:
            print('不认识')
    
64.    静态方法和类方法区别?
        
    静态方法 : 相当于在类作用域下的普通函数,不进行与类或实例相关的操作
        静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互,即在静态方法中,
        不会涉及到类中的方法和属性的操作
    @staticmethod
    def func():
        pass
    类方法 : 类方法不是绑定到对象上,而是绑定在类上的方法。它的第一个参数是这个类本身(记住:类也是对象)。
    @classmethod
    def func(cls):
        pass
    
65.    列举面向对象中的特殊成员以及应用场景
    __call__:一个对象是否可以被调用,取决于对象是否有__call__方法
    __getitem__,__setitem__,delitem__:
        class SpecialMembers:
          # 当执行obj['value']的时候就会自动执行__getitem__方法,并且把对象括号内的值当做__getitem__的值
          def __getitem__(self, item):
            print(item)
          def __setitem__(self, key, value):
            print(key, value)
          def __delitem__(self, key):
            print(key)

        obj = SpecialMembers()  # 创建一个对象
        obj['value']  # 自动执行__getitem__方法
        obj['k1'] = "values"  # 自动执行__setitem__方法
        del obj['key']  # 自动执行__delitem__方法
    __dict__:
        class SpecialMembers:
          """
          类的注释
          """
          def __init__(self):
            self.Name = "Ansheng"
            self.Blog = "1234"

        print(SpecialMembers.__dict__)  # 获取类中的成员
        obj = SpecialMembers()  # 创建一个对象
        print(obj.__dict__)  # 获取对象中的成员
    
    __iter__: 一个对象如果可以被for循环迭代时,说明对象中由__iter__方法,且方法中有yield值。
        class SpecialMembers:
        def __iter__(self):
            yield 1
            yield 2
            yield 3
        # 创建一个对象
        obj = SpecialMembers()
        # 如果执行for循环对象时,自动会执行对象的__iter__方法,此时的__iter__就是一个生成器
        for i in obj:
          print(i)
    
66.    1、2、3、4、5 能组成多少个互不相同且无重复的三位数
    for x in range(1,6):
    for y in range(1,6):
        for z in range(1,6):
            if (x != y) and (x != z) and (y != z):
                print(x, y, z)
                
67.    什么是反射?以及应用场景?
    利用字符串获取对象的属性或方法,WEB框架的CBV,配置文件获取类
    使用字符串数据类型的变量名,访问一个命名空间中的名字
    hasattr()
    getattr()
    class A:
        role = 'person'
        def func(self):
            print('1')
    print(getattr(A,'role')) #person,找一个属性,直接找到这个属性的值
    f = getattr(A,'func');f(1) #1,找一个方法,找到这个方法的内存地址
    getattr(A,'func')(1)  #1  A.func(1)
    以后hasattr 应该和getattr配对使用,先判断存在是否,存在则使用getattr访问属性或方法。
    
    import os
    # os.rename('log','log_bak')
    getattr(os,'rename')('log','log_bak')
    从自己的模块中使用自己的模块中的名字:
    getattr(模块名,类名)
    
68.    metaclass作用?以及应用场景?
    class Foo(metaclass=abc.ABCMeta):  # 继承了metaclass=abc.ABCMeta的就叫抽象类
        @abc.abstractmethod  #抽象类中用@abc.abstractmethod装饰的叫抽象方法
        def f2(self):  # 无需实现功能
            pass
    class Bar(Foo): #继承了抽象类,则必须实现抽象方法,不实现则报错(实例化的时候报错)
        def f2(self):
            print(111)
    所以抽象类是用来做约束的:它的特殊之处在于只能被继承,不能被实例化
    应用场景:
        在
        
69.    用尽量多的方法实现单例模式。
    # 基于__new__实现
    class A(object):
        __instance = None
        def __new__(cls,*args,**kwargs):
            if cls.__instance is None:
                obj = object.__new__(cls)
                cls.__instance = obj
            return cls.__instance
        def __init__(self,name,age):
            self.name = name
            self.age = age
    # 使用类    
    class Singleton(object):
        def __init__(self):
            pass
        @classmethod
        def instance(cls,*args,**kwargs):
            if not hasattr(Singleton,'_instance'):
                Singleton._instance = Singleton(*args,**kwargs)
            return Singleton._instance
        
70.    装饰器的写法以及应用场景。
    from functools import wraps
    def wrapper(f):
        @wraps(f)
        def inner(*args,**kwargs):
            """被装饰函数之前"""
            ret = f(*args,**kwargs)
            """被装饰函数之后"""
            return ret
        return inner
    
    @wrapper   #func = wrapper(func)  func = inner
    def func():
        pass
    
71.    异常处理写法以及如何主动跑出异常(应用场景)
    # 多分支异常
    try:
        pass
    except ERRORTYPE1:
        pass
    except ERRORTYPE2 as e:
        pass
    # 万能异常
    try:
        pass
    except Exception:
        pass
    # try ... except .... else... try中的代码没有触发任何异常,则执行else里面的语句
    try:
        pass
    except NameError:
        pass
    else:
        pass
    # finally 不管try中的代码是否有异常都会执行finally
    def func():
        try:
            return 1
        finally:
            print("finally")
    func() #finally
        #在函数中遇到return函数就结束,但是依旧会执行finally中的内容
        #finally一般做清理工作。
    
    # 主动抛出异常
    class Payment:
        def pay(self,money):
            raise NotImplementedError("没有实现pay方法")   # 基类中定义抛出异常,子类中必须要实现
    class AliPay(Payment):
        def pay(self,money):
            print('支付宝支付了%s元' %money)
    class WechatPay(Payment):
        def fuqian(self,money):   # 子类中未实现,抛出错误
            print("微信支付了%s元" %money)
    def pay(obj,money):
        obj.pay(money)

    we = WechatPay()
    pay(we,10)
    
    # 自定义异常
    class DatabaseException(Exception):
        def __init__(self,err):
            Exception.__init__(self)
            self.errinfo = err
        def __str__(self):
            return self.errinfo

    def oper_db():
        # 操作数据库的时候出现问题,直接抛出异常
        raise DatabaseException('数据库异常')
    if __name__ == "__main__":
        try:
            oper_db()
        except DatabaseException as e:
            print(e)  # __str__()
    
    
72.    什么是面向对象的mro
    mro:方法解析顺序,在多继承中,其方法和属性可能定义在当前类中,也可能来自基类,所以在
    调用的时候就需要去搜索以确定位置。而搜索的顺序就是mro。
    在Python2中是经典类:用深度优先,从左至右的深度优先遍历。inspect.getmro(D)
    在python3中是新式类:用广度优先,因此新式类可以直接通过 __mro__ 属性获取类的 MRO。D.mro()
    
73.    isinstance作用以及应用场景?
    1.    isinstance(obj,type) 的作用是判断对象的类型,判断已知类型的对象
        type(obj)是判断未知对象的类型
    2.    isinstance(obj,class)  判断一个对象和一个class有没有血缘关系,继承也可以
        type(obj) is class    不能检测到血缘关系,只能检测到,只能单纯的检测到对象的类
        
        issubclass(Son,Parent):检测类和类的继承关系
    
74.    写代码并实现:
    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]
    # 最简单的方法就是两层for循环
    lis = [1,2,3,4,5]
    target = 9
    for i in range(len(lis)):
        for j in range(i,len(lis)):
            if lis[i]+lis[j] ==target:
                return i,j
    # 用target减去循环的元素,然后判断得到的值是否在dic中,如果在直接返回dic的值(索引),
    def sum2(li, target):
        dic = {}
        for i,v in enumerate(li):
            b = target - v
            if b in dic:
                return dic[b],i
            else:
                dic[v] = i
        
    li = [1,2,3,4,5]
    print(sum2(li,8))
    
75.    json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?
    字符串,数字,列表,字典,布尔值,None
    
    自定义cls类
    class MyEncoder(json.JSONEncoder):
        def default(self, o): # o是数据类型
            if isinstance(o,datetime.datetime):
                return o.strftime('%Y-%m-%d')
            else:
                return super(MyEncoder,self).default(o)
            
76.    json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
    import json
    dic = {'1':'你好'}
    print(json.dumps(dic,ensure_ascii=False))  # {"1": "你好"}
    print(json.dumps(dic))  # {"1": "\u4f60\u597d"}
    
77.    什么是断言?应用场景?
    断言 assert 相当于与if,但是不需要缩进
    eg:
        assert 1==2   
        print('1==2')
    断言成立就继续往下执行,断言不成立就报错AssertionError
    使用场景,一般的if判断就可以替换为断言,但是需要try
    
78.    有用过with statement吗?它的好处是什么?
    有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。
    一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。
    如果不用with:一是可能忘记关闭文件句柄;二是文件读取数据发生异常,没有进行任何处理。
    
    Python对with的处理还很聪明。基本思想是with所求值的对象必须有一个enter()方法,一个exit()方法。
    紧跟with后面的语句被求值后,返回对象的enter()方法被调用,这个方法的返回值将被赋值给as后面的变量。
    当with后面的代码块全部被执行完之后,将调用前面返回对象的exit()方法。
    
    class Sample:
        def __enter__(self):
            print("In__enter__()")
            return "Foo"
        def __exit__(self, type,value, trace):
            print("In__exit__()")
    def get_sample():
        return Sample()

    with get_sample() as sample:
        print("sample:",sample)  
    #In__enter__()
    # sample: Foo
    # In__exit__()
    
    with open
    
79.    使用代码实现查看列举目录下的所有文件。
    import os
    def file_list(dir):
        if os.path.exists(dir):
            list1 = os.listdir(dir)
            for i in list1:
                if os.path.isfile(os.path.join(dir,i)):
                    print(i)
                else:
                    file_list(os.path.join(dir,i))
    file_list(r'C:\Users\ASIA\Desktop')
    
    import os
    def get_size(dir):
        sum_size = 0
        for item in os.listdir(dir):
            path = os.path.join(dir,item)
            if os.path.isfile(path):
                sum_size += os.path.getsize(path)
            else:
                sum_size += get_size(path)
        return sum_size
    
80.    简述 yield和yield from关键字。
    若一个函数中加入了yield语句,那么这个函数就被增强了,变成了一个生成器:generator。
    对于一个函数,其程序执行到了yield语句,那么它选择了中断,返回一个结果(就是yeild后面的内容),
    这个函数被中断,然后随着生成器的next的执行,该函数继续从中断的地方执行。
    
    生成器方法调用时,不会立即执行。需要调用next()或者使用for循环来执行。使用for循环不需要自己捕获StopIteration异常。使用next()方法,当生产器方法执行结束会抛出StopIteration异常(只要不是使用yield返回数据,都会抛出StopIteration异常)。

    yield 可以返回结果
    yield from 可以返回一个新的迭代器

    def g1(x):
        yield range(x)
    def g2(x):
        yield from range(x)
    it1 = g1(5)
    it2 = g2(5)
    print(it1)  # generator
    print(it2)  # generator
    print([x for x in it1])
    # [range(0, 5)]
    for i in it1:
    print(i)  # range(0, 5)
    for j in i:
        print(j) # 0-4
        
    print([x for x in it2])
    # [0, 1, 2, 3, 4]
    yield 返回一个生成器,就是range自身
    yield 也返回一个生成器,这个生成器是由range代理的

81、logging模块的基本使用
    import logging
    logger = logging.getLogger()  #实例化,创建logger对象
    fh = logging.FileHandler('test.log',encoding="utf-8") #实例化一个文件句柄,默认mode为a
    src = logging.StreamHandler()  #往屏幕上输出,创建屏幕句柄

    #设置格式
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    #句柄关联的格式
    fh.setFormatter(formatter)
    src.setFormatter(formatter)

    #logger关联的句柄
    logger.addHandler(fh)
    logger.addHandler(src)

    单对文件流设置某个级别:
    src.setLevel(logging.WARNING) #设置屏幕输出为warning以上
    对logger设置级别:
    logger.setLevel(logging.DEBUG) #设置debug及以上输出

    logger.warning("warning info")  #写入文件中和屏幕中
    logger.debug("logger debug infor")
    logger.critical('logger critical message')

82、利用time模块计算时间差?
    import time
    true_time=time.mktime(time.strptime('2017-09-11 08:30:00', '%Y-%m-%d %H:%M:%S'))  # 先把格式化时间转为结构化时间,然后将结构化时间转为timestamp
    time_now=time.mktime(time.strptime('2017-09-11 08:30:59', '%Y-%m-%d %H:%M:%S'))
    dif_time=time_now-true_time  # 时间戳相减
    struct_time=time.localtime(dif_time)  # 最后将时间戳转换为结构化时间
    print('过去了%d年%d月%d天%d小时%d分钟%d秒'%(struct_time.tm_year-1970,struct_time.tm_mon-1,
                                           struct_time.tm_mday-1,struct_time.tm_hour,
                                           struct_time.tm_min,struct_time.tm_sec))
                                                                                
83.re模块
    re.findall(pattern,str)        # 查找所有,放在list中,用group取值,
    re.search(pattern,str)        # 找到一个就返回,找不到None,用group取值
    re.match(pattern,str)        # pattern变为^pattern,找不到返回None,用group取值
    obj = re.compile(pattern,re.S)    # 将pattern编译成一个正则表达式对象,re.S表示.可以匹配任意字符,包括换行
    ret = obj.search(str)        # 对象调用去search
    re.finditer(pattern,str)    # 返回一个迭代器,取值next(ret).group()
    # 只有findall中才有分组优先:
    re.findall('www.(baidu|sina).com', 'www.baidu.com')   # baidu
    re.findall('www.(?:baidu|sina).com', 'www.baidu.com') #取消分组优先,www.baidu.com
    
    re.split('\d+',"eva3egon4yuan")  # ['eva', 'egon', 'yuan']
    re.split("(\d+)","eva3egon4yuan") #['eva', '3', 'egon', '4', 'yuan']
    
    # 分组命名
    ret = re.search('<(?P<tag>\w+)>(?P<content>\w+)</(?P=tag)>','<h1>hello</h1>')
    print(ret.group()) #<h1>hello</h1>
    print(ret.group('tag')) #h1
    print(ret.group("content")) #hello
    

    

猜你喜欢

转载自www.cnblogs.com/yazhou-lai/p/9763555.html