• python面试题解析(python基础篇80题)


    1. 答:出于编程的喜爱,以及行业本身的前瞻性,创造性,优越性,越是综合的科目越能检验一个人的能力,喜欢这种有挑战的事情。
    2. 答:跟随老师学习,以及自己查询资料,结合实战,进行输入输出以及纠正。
    3. 答:python是强类型加动态语言,自带有丰富的库,可以进行直接调用,无需重复造轮子,缺点是运行相同的程序,速度远慢于其它类型语言。
    4. 答:编译型语言是指在运行前先由编译器将高级语言代码编译为对应机器的cpu汇编指令集,再由汇编器汇编成目标机器码,生成可执行文件,然后最后运行生成的可执行文件。

    解释型在运行时由翻译器将高级语言代码翻译成易于执行的中间代码,并由解释器逐一将该中间代码解释成机器码并执行。

    1. 答:Cpython,由C语言开发,在命令行下运行python就是启动Cpython。

    Ipython,基于Cpython之上的一个交互性解释器,执行方式与Cpython相同。

    PyPy,以执行速度为目标的解释器,采用JIT技术,对python代码进行动态编译,绝大多数代码可以在PyPy下运行。

    Jpython,运行在java平台的python解释器,可以直接把python代码编译成java字节码执行。

    1. 答:8位(bit)=1个字节(byte),位是计算机内部数据存储的最小单位,字节是计算机中数据处理的基本单位,计算机中以字节位单位存储和解释信息,规定一个字节由8个二进制位构成。
    2. 答:8bit = 1byte =1/1024kb = 1/ 1024^2mb = 1/1024^3GB
    3. 答:缩进使用4个空格,或者IDE中以TAB键当做4个空格。

    所有行限制为最多79个字符

    两个空白行围绕顶层函数和类定义

    核心代码应始终使用UTF-8,所有标识符使用纯ascii标识符,并且应尽可能使用英文单词。

    Import接口通常应该分开,导入始终放在文件的顶部,紧跟在任何模块注释和文档字符串之后,模块全局变量和常量之前。

    1. 答:

    v = int('0b1111011', 2)
    print(v)

    v1 = bin(18)
    print(v1)
    v2 = int('011', 8)
    print(v2)
    v3 = oct(30)
    print(v3)
    v4 = int('0x12', 16)
    print(v4)
    print(hex(87))

    10.答:

    a = "10.3.9.12"


    def func(ip):
        Iplist = ip.split(".")  # ['10', '3', '9', '12']
        res = " "
        temp = []
        for i in Iplist:  # <class 'str'>
            i = int(i)  # <class 'int'>
            i = bin(i)[2:]  # <class 'str'>
            temp.append(i.rjust(8, "0"))  # 右对齐,向左填充数据
        res = res.join(temp)
        return res


    b = "".join([" ".join(str(bin(int(i))[2:]).rjust(8, "0") for i in a.split("."))])
    print(func(a))

    11. 答:997层

    12.答:1(布尔或:如果x是True,它返回x的值,否则它返回y的计算值。)               
    3(x and y 布尔"与" - :
    如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。)              

          0

          1

          1

          False

    13.答:ascii编码是一个字节,unicode通常是2个字节,GBK则是第一个字节是大于127就固定表示这是一个汉字的开始。Utf-8是每次8个位传输数据,utf-16 就是每次16个位。

    14.      答:机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写,一般从业人员接触不到。

          字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。

    15.答: var = 1 if 条件成立else 2

    16.答:1. 性能

      - Py3.x性能比Py2.5慢15%,但还有很大的提升空间。

    2.编码

      - Py3.X源码文件默认使用utf-8编码

    3. 语法

      - 去除print语句

      - 关键词加入as 和with,还有True,False,None

      - 删除了raw_input,用input代替

      - 新的metaclass语法

    4. 字符串和字节串

      - 字符串只有str一种类型

    5.数据类型

      - 只有一种整型——int

      - 新增了bytes类型

    6.面向对象

      - 容器类和迭代器类被ABCs化,所以cellections模块里的类型比Py2.5多了很多

      - 迭代器的next()方法改名为__next__(),并增加内置函数next(),用以调用迭代器的__next__()方法

    17.答: b, a = a,b

    18.  答:int <= 32 位整数
    long > 32 位整数

    19. 答:两者的区别是xrange返回的是一个可迭代的对象,range返回的则是一个列表. 同时效率更高,更快。

      - 原因是实现的时候使用了 yield(此为python2.x回答,python3已删除xrange)

    20. 答:xreadlines = 返回一个生成器对象,

    readlines =  遍历文件所有行

    21.答:

    //     alert(new Boolean(0));  //false

    //     alert(new Boolean(-0)); // false

    //     alert(new Boolean(null)); // false

    //     alert(new Boolean(NaN)); // false

    //     alert(new Boolean(undefined)); // false

    //     alert(new Boolean("undefined")); // true

    //     alert(new Boolean("")); // false

    //     alert(new Boolean(false)); // false

    //     alert(new Boolean("false")); // true

    22. 答:

          列表:list

        - list.append(obj) # 在列表末尾添加新的对象

        - list.count(obj)  # 统计某个元素在列表中出现的次数

        - list.extend(seq) # 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)

        - list.index(obj)  # 从列表中找出某个值第一个匹配项的索引位置

        - list.insert(index, obj)# 将对象插入列表

        - list.pop(obj=list[-1]) # 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值

        - list.remove(obj) # 移除列表中某个值的第一个匹配项

        - list.reverse()   # 反向列表中元素

        - list.sort([func])# 对原列表进行排序

        - list.clear()     # 清空列表

        - list.copy()      # 复制列表

    字典:dict

        - popitem()    # 随机返回并删除字典中的一对键和值(一般删除末尾对)。

        - key in dict  # 如果键在字典dict里返回true,否则返回false

        - radiansdict.copy()   # 返回一个字典的浅复制

        - radiansdict.keys()   # 以列表返回一个字典所有的键

        - radiansdict.items()  # 以列表返回可遍历的(键, 值) 元组数组

        - radiansdict.clear()  # 删除字典内所有元素

        - radiansdict.values() # 以列表返回字典中的所有值

        - radiansdict.fromkeys()    # 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值

        - radiansdict.update(dict2) # 把字典dict2的键/值对更新到dict里

        - radiansdict.get(key, default=None)        # 返回指定键的值,如果值不在字典中返回default值

        - radiansdict.setdefault(key, default=None) # 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default

        - pop(key[,default])   # 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。否则,返回default值。

    字符串:str

        - upper()      # 转换字符串中的小写字母为大写。

        - title()      # 返回"标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())。

        - lower()      # 转换字符串中所有大写字符为小写。

        - rstrip()     # 删除字符串字符串末尾的空格.

        - lstrip()     # 截掉字符串左边的空格或指定字符。

        - max(str)     # 返回字符串 str 中最大的字母。

        - min(str)     # 返回字符串 str 中最小的字母。

        - join(seq)    # 以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串

         ...

        MySlef

    整数:int

        - bit_length()  # 查询以二进制表示一个数字的值所需的位数

        - int.from_bytes(bytes,byteorder)  # 返回给定字节数组所表示的整数。

        - int.to_bytes(length,byteorder)   # 返回表示整数的字节数组。

    元组:tuple

        - len(tuple) # 计算元组元素个数。

        - max(tuple) # 返回元组中元素最大值。

        - min(tuple) # 返回元组中元素最小值。

        - tuple(seq) # 将列表转换为元组。

    集合:set

        - set1 = set({1, 2, 'barry'}) # 创建集合

        - set2 = {1, 2, 'barry'}      # 创建集合

        - add  # 将元素添加到集合中。如果元素已经存在,这不起作用。

        - del set1  # 删除集合- update # 迭代增加

        - clear  # 删除此集合中的所有元素

        - remove # 删除一个元素

        - pop    # 随机删除一个元素

        - issubset    # 子集

        - issuperset  # 超集

        - union  # 并集。(| 或者 union)

        - difference # 差集。(- 或者 difference)

        - intersection  # 交集。(&  或者 intersection)

        - isdisjoint    # 如果两个集合有一个空交点,则返回True

        - intersection_update  # 用它自己和另一个交集更新一个集合。

        - difference_update  # 删除另一个集合中本集合所拥有的所有元素

        - symmetric_difference  # 反交集。(^ 或者 symmetric_difference)

    浮点:float

        - is_integer # 如果浮点数是整数,则返回True

    collections:Python内建的一个集合模块,提供了许多有用的集合类。

        - Counter     # 是一个简单的计数器,例如,统计字符出现的个数:

        - OrderedDict # 可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key:

        - deque       # 是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

        - defaultdict # 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:

    23. 答:

    my_lambda = lambda arg : arg + 1

    匿名函数主要是和其它函数搭配使用,不需要显示指定函数名。

    24. 答:

    - 1. 不做任何事情,一般用做占位语句。

     - 2. pass是空语句,是为了保持程序结构的完整性。

    25. 答:

    位置参数(positional argument)

    关键词参数(keyword argument)

      - *args表示任何多个无名参数,它本质是一个 tuple ;

      - **kwargs表示关键字参数,它本质上是一个 dict ;

      - 并且同时使用*args和**kwargs时,必须*args参数列要在**kwargs前。

    26. 答:

    - is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。莱布尼茨说过:“世界上没有两片完全相同的叶子”,这个is正是这样的比较,

    比较是不是同一片叶子(即比较的id是否相同,这id类似于人的身份证标识)。

      - == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。这里比较的并非是同一片叶子,可能叶子的种类或者脉络相同就可以了。

           默认会调用对象的 __eq__()方法。

    27.答:浅拷贝:只拷贝父对象,不会拷贝对象的内部的子对象(父对象不同,子对象进行引用,ID相同)深拷贝:拷贝对象及其子对象(父, 子对象不同) 由于深拷贝需要维护一个 memo 用于记录已经拷贝的对象,所以这也是它比较慢的原因

    deepcopy优化版:

    class FiveCardStudInfo(roomai.abstract.AbstractInfo):

        public_state = None

        person_state = None

        def __deepcopy__(self, memodict={}):

            info = FiveCardStudInfo()

            info.public_state = self.public_state.__deepcopy__()

            info.public_state = self.person_state.__deepcopy__()

            return info

    28. 答:

    引用计数

    原理:当一个对象的引用被创建或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1,当对象的引用计数减少为0时,就意味着对象已经再没有被使用了,可以将其内存释放掉。

    优点:引用计数有一个很大的优点,即实时性,任何内存,一旦没有指向它的引用,就会被立即回收,而其他的垃圾收集技术必须在某种特殊条件下才能进行无效内存的回收。

    缺点:但是它也有弱点,引用计数机制所带来的维护引用计数的额外操作与Python运行中所进行的内存分配和释放,引用赋值的次数是成正比的,这显然比其它那些垃圾收集技术所带来的额外操作只是与待回收的内存数量有关的效率要低。同时,引用技术还存在另外一个很大的问题-循环引用,因为对象之间相互引用,每个对象的引用都不会为0,所以这些对象所占用的内存始终都不会被释放掉。如下:

    a = []

    b = []

    a.append(b)

    b.append(a)

    print a

    [[[…]]]

    print b

    [[[…]]]

    标记-清除

    标记-清除只关注那些可能会产生循环引用的对象,显然,像是PyIntObject、PyStringObject这些不可变对象是不可能产生循环引用的,因为它们内部不可能持有其它对象的引用。Python中的循环引用总是发生在container对象之间,也就是能够在内部持有其它对象的对象,比如list、dict、class等等。这也使得该方法带来的开销只依赖于container对象的的数量 

    原理:1. 寻找跟对象(root object)的集合作为垃圾检测动作的起点,跟对象也就是一些全局引用和函数栈中的引用,这些引用所指向的对象是不可被删除的;2. 从root object集合出发,沿着root object集合中的每一个引用,如果能够到达某个对象,则说明这个对象是可达的,那么就不会被删除,这个过程就是垃圾检测阶段;3. 当检测阶段结束以后,所有的对象就分成可达和不可达两部分,所有的可达对象都进行保留,其它的不可达对象所占用的内存将会被回收,这就是垃圾回收阶段。(底层采用的是链表将这些集合的对象连接在一起)

    缺点:标记和清除的过程效率不高。

    分代回收

    原理:将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,Python默认定义了三代对象集合,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。

    29. 答:可变:

      - list,  - dict

    不可变:

      -str,  - int,  - tuple,  - float,

    30.答 {'k1': [666], 'k2': [666]}

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

    31.答:[2, 2, 2, 2]

    32. 答:map, filter, zip ,isinstance

    33. 答:

    map:遍历序列,对序列中每个元素进行操作,最终获取新的序列。

      - 每个元素增加100:

        - li = [11, 22, 33]

        - new_list = map(lambda a: a + 100, li)

      - 两个列表对应元素相加

        - li = [11, 22, 33]

        - sl = [1, 2, 3, 4]

        - new_list = map(lambda a, b: a + b, li, sl)

    filter:对于序列中的元素进行筛选,最终获取符合条件的序列。

      - 获取列表中大于12的所有元素集合

        - li = [11, 22, 33]

        - new_list = filter(lambda arg: arg > 22, li)

        - # filter第一个参数为空,将获取原来序列

    reduce:对于序列内所有元素进行累计操作。

      - 获取序列所有元素的和

        - li = [11, 22, 33]

        - result = reduce(lambda arg1, arg2: arg1 + arg2, li)

      - # reduce的第一个参数,函数必须要有两个参数

      - # reduce的第二个参数,要循环的序列

      - # reduce的第三个参数,初始值

    34. 答:

    print('
    '.join([' '.join(['%s*%s=%-2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))

    35. 答:

          可通过pip install 模块名来进行联网安装。

          第三方模块,request,django, tornado,flask, redis等等。

    36.      答:time&datetime模块,random模块,os模块,sys模块,shutil模块,json&pickle模块,shelve模块,xml模块,configParser模块,hashlib模块,subprocess模块,logging模块,re模块。

    37. 答:

    Match 从头开始匹配,search匹配包含。

    38. 答:

          贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配

    39. 答:a.    [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]

          b.<generator object <genexpr> at 0x012C4EA0>

    40. 答:a. 1

          b.2

          c.False

          d.True

    41. 答:函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储,所以三次执行的结果就是 [1, 1, 1] ,想每次执行只输出[1] ,默认参数应该设置为None。

    42. 答:list("1,2,3".split(','))

    43. 答:[int(x) for x in ['1','2','3']]

    44.答:列表与列表内包含元祖,以及包含多个元祖。

    45. 答:[i*i for i in range(1,11)]

    46. 答:list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))

    47. 答:1 声明法

    在文件开头声明全局变量variable,

    在具体函数中使用该变量时,需要事先声明 global variable,否则系统将该变量视为局部变量。

    2模块法(推荐)

    把全局变量定义在一个单独的模块中:
    #gl.py
    gl_1 = 'hello'
    gl_2 = 'world'

    在其它模块中使用
    #a.py
    import gl

    def hello_world()
        print gl.gl_1, gl.gl_2

    #b.py
    import gl

    def fun1()
        gl.gl_1 = 'Hello'
        gl.gl_2 = 'World'

    48.答:记录日志,并且日志汇总包含的信息即有正常的程序访问日志,还可能有错误,警告等信息输出,应用场景主要有5个level。

    DEBUG,INFO,WARNING,ERROR,CRITICAL。

    49. 答:

    1. Stack() 创建一个新的空栈

    2. push(item) 添加一个新的元素item到栈顶

    3. pop() 弹出栈顶元素

    4. peek() 返回栈顶元素

    5. is_empty() 判断栈是否为空

    6. size() 返回栈的元素个数

    class Stack(object):

        """栈"""

        def __init__(self):

             self.items = []

        def is_empty(self):

            """判断是否为空"""

            return self.items == []

        def push(self, item):

            """加入元素"""

            self.items.append(item)

        def pop(self):

            """弹出元素"""

            return self.items.pop()

        def peek(self):

            """返回栈顶元素"""

            return self.items[len(self.items)-1]

        def size(self):

            """返回栈的大小"""

            return len(self.items)

    if __name__ == "__main__":

        stack = Stack()

        stack.push("hello")

        stack.push("world")

        stack.push("lcg")

        print stack.size()

        print stack.peek()

        print stack.pop()

        print stack.pop()

        print stack.pop()

    50. 答:

    Python的字符串格式化常用的有三种

      第一种:最方便的

      缺点:需一个个的格式化

    print('hello %s and %s' % ('df', 'another df'))


      第二种:最好用的

      优点:不需要一个个的格式化,可以利用字典的方式,缩短时间

    print('hello %(first)s and %(second)s' % {'first': 'df', 'second': 'another df'})
      第三种:最先进的

        优点:可读性强

    print('hello {first} and {second}'.format(first='df', second='another df'))

    51. 答:

    容器:

       - 是一系列元素的集合,str、list、set、dict、file、sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象。

    可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。

    迭代器:

        - 持有一个内部状态的字段,用于记录下次迭代返回值,它实现了__next__和__iter__方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。

    生成器:

        - 是一种特殊的迭代器,它的返回值不是通过return而是用yield。

    装饰器

    - 在不改变原函数代码的基础上,在执行前后进行定制操作

    52. 答:

    li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


    def search(someone, li):
        l = -1
        h = len(li)

        while l + 1 != h:
            m = int((l + h) / 2)
            if li[m] < someone:
                l = m
            else:
                h = m
        p = h
        if p >= len(li) or li[p] != someone:
            print("元素不存在")
        else:
            str = "元素索引为%d" % p
            print(str)


    search(3, li)  # 元素索引为2

    53. 答:def foo():

        m, n=3, 5

        def bar():

            a=4

            return m+n+a

        return bar

    >>>bar =  foo()

    >>>bar()

    说明:

    bar在foo函数的代码块中定义。我们称bar是foo的内部函数。

    在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。

    简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。

    - 闭包的意义与应用:延迟计算;

    - 闭包的意义:      返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

    #应用领域:延迟计算(原来我们是传参,现在我们是包起来)

    装饰器就是闭包函数的一种应用场景

    54. 答:os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。

    55. 答:使用random模块可以很容易生成随机字符串。

    56. 答:os 模块中使用os.remove()来删除一个文件。

    57. 答:- 简单描述:继承、封装、多态

    - 系统描述:先对代码进行分类:按属性进行划分(file,DB),按功能划分,将同一类方法分为一类。将方法中共同的参数封装到对象中,把共用值封装到对象中。

    面向对象的私有字段:

      - python中一切皆对象

      1. 封装:对数据的,对对象的封装。

      2. 继承:在类的基础上进行二次开发,通过函数super() 或者"基类名.方法名() "的方式实现这一目的的。

      3. 多态:同一个方法处于不同对象中,可以产生不同的结果

    - 多态示例

    # 鸭子模型

      class A:

          def send(self):

              pass

      class B:

          def send(self):

              pass

          def func(arg):

              arg.send()

              obj = B()

      func(obj)

    58. 答:继承指的是类与类之间的关系,是一种“是”什么的关系,继承的功能之一就是解决代码重用问题,python中的继承可分为单继承和多继承。

    59. 答:新式类跟经典类的差别主要是以下几点:

      1. 新式类对象可以直接通过__class__属性获取自身类型:type

      2. 继承搜索的顺序发生了改变,经典类多继承属性搜索顺序:

          - 先深入继承树左侧,再返回,开始找右侧;

          - 新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动。

            ps:(经典类深度优先,新式类广度优先)

      3. 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中。

      4. 新式类增加了__getattribute__方法

    Python 2.x中默认都是经典类,只有显式继承了object才是新式类

    Python 3.x中默认都是新式类,不必显式的继承object

    60. 答:子类继承父类的方法,其继承顺序按照 __mro__来定义

    61.答:

    1. functools模块的引用

    from functools import partial

    2. functools模块的组成

    • partial(func, *args, **keywords)

    通过封装,重新定义已有的函数,如增减参数、设置初始值或改变返回值。
    该函数的返回partial对象,其中包含3个只读属性:

      • partial.func
      • partial.args
      • partial.keywords
      • @total_ordering

    修饰class
    实现多个比较操作方法,如__eq__, __lt__等

    • @lru_cache(maxsize=128, typed=False)

    修饰方法,重新定义已有的函数
    只存在于内存中

    • @singledispatch(default)

    修饰方法
    将函数转换为 single-dispatch generic function

    • @wraps(wrapped_func, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

    调用update_wrapper()方法的简便实现

    • update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
    • reduce(function, iterable[, initializer])
    • cmp_to_key(func)

    Python的functools模块用以为可调用对象(callable objects)定义高阶函数或操作。简单地说,就是基于已有的函数定义新的函数。
    所谓高阶函数,就是以函数作为输入参数,返回也是函数。

    62. 答:- 双下划线:

      1. __getattr__:反射

         应用场景:

           - CBV

           - Django 配置文件

           - wtforms中的Form()实例化中将"_fields中的数据封装到Form类中"

      2. __mro__:定义解析类继承的顺序

         应用场景:wtforms中 FormMeta中继承的优先级

      3. __dict__:用来存储对象属性的一个字典,其键为属性名,值为属性的值

         - __dict__ 与 dir()的区别:

           1. dir()是一个函数,返回值是list

           2. dir用来寻找一个对象的所有属性值,包括__dict__中的属性,__dict__是dir()的子集

      4. __new__ :

         - 当你继承一些不可变的class时(比如int, str, tuple),提供给你一个自定义这些类的实例化过程的途径。

         - 实现自定义 metaclass

         应用场景:

           - wtforms 字段实例化时返回:不是StringField,而是UNboundField

           - rest_framework:many=Ture 中的序列化

           - 单例模式

      5. __call__:作用是使实例能够像函数一样被调用,同时不影响实例本身的生命周期, (__call__()不影响一个实例的构造和析构)

                   但是__call__()可以用来改变实例的内部成员。

         __call__ 与 __init__的区别

         应用场景:

           - FLask 请求的入口app.run()

           - 字段生成标签时:字段.__str__ ==> 字段.__call__ ==> 插件.__call__

      6. __iter__:

         迭代器为什么要一定实现__iter__方法(为什么要返回自身)

         应用场景:wtforms中BaseForm中循环所有字段时自定义了__iter__方法

    63. 答:from types import MethodType,FunctionType

    class func(object):

        def foo(self):

            print(1)

    Fun = func()

    print(type(func.foo))

    >>> <class 'function'>

    print(type(Fun.foo))

    >>> <class 'method'>

    print(isinstance(func.foo,FunctionType))

    >>> True

    print(isinstance(Fun.foo,MethodType))

    >>> True

    通过类去调用函数foo时,不需要传self参数。此时foo为函数

    如果通过对象Fun去调用foo时,对象自动传参self。而foo则是一个方法

    64. 答:一、先是在语法上面的区别:
    1、静态方法不需要传入self参数,类成员方法需要传入代表本类的cls参数;
    2、静态方法是无妨访问实例变量和类变量的,类成员方法无法访问实例变量但是可以访问类变量
    二、使用的区别:
    由于静态方法无法访问类属性,实例属性,相当于一个相对独立的方法,跟类其实并没有什么关系。这样说来,静态方法就是在类的作用域里的函数而已。
     
    65. 答:1.
    __doc__
    描述类的信息


    class Foo(object):
        # 单引号和双引号都可以 
        """这里描述类的信息"""

       
    def func(self):
            pass


    print(Foo.__doc__)


    2.
    __call__
    对象后面加括号,触发执行


    # __call__方法的执行是由对象加括号触发的,即:对象()或者 类()()
    class Foo(object):
        def __call__(self, *args, **kwargs):
            print("running call", args, kwargs)


    foo = Foo()
    foo(1, 2, 3, name="UserPython")

    Foo()(1, 2, 3, name="UserPython")

    3.
    __dict__
    查看类或对象中的所有成员


    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age


    foo = Foo("UserPython", 17)

    print(Foo.__dict__)  # 打印类里的所有属性,不包括实例属性
    print(foo.__dict__)  # 打印所有实例属性,不包括类属性
    显示的结果:

    {‘__weakref__‘: < attribute ‘__weakref__‘ of ‘Foo‘ objects >, ‘__init__‘: < function
    Foo.__init__
    at
    0x0000000000BB0730 >, ‘__dict__‘: < attribute ‘__dict__‘ of ‘Foo‘ objects >, ‘__module__‘: ‘__main__‘, ‘__doc__‘: None}
    {‘name‘: ‘UserPython‘, ‘age‘: 17}

    4.
    __str__
    如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值


    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age

        def __str__(self):
            return "<obj:%s>" % self.name


    foo = Foo("UserPython", 17)

    print(foo)  # >>><obj:UserPython>
    显示的效果为:

    < obj:UserPython >

    5.
    __getitem__ 、 __setitem__ 、__delitem__
    用于索引操作,如字典。分别表示获取、设置、删除数据


    class Foo(object):

        def __getitem__(self, key):
            print("__getitem__", key)

        def __setitem__(self, key, value):
            print("__setitem__", key, value)

        def __delitem__(self, key):
            print("__delitem__", key)


    foo = Foo()
    foo["name"] = "UserPython"  # >>>__setitem__ name UserPython  触发__setitem__
    foo["name"]  # >>>__getitem__ name  触发__getitem__
    del foo["name"]  # >>>__delitem__ name  触发__delitem__


    6.
    __new__ 、__metaclass__


    class Foo(object):

        def __init__(self, name):
            self.name = name


    foo = Foo("UserPython")
    ‘‘‘‘‘
    上述代码中,foo是通过Foo类实例化的对象,其实,不仅foo是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
    如果按照一切事物都是对象的理论:foo对象时通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建。
    ‘‘‘

    print(type(foo))
    print(type(Foo))
    # 所以,foo对象是Foo类的一个实例,Foo类对象是type类的一个实例,即:Foo类对象是通过type类的构造方法创建。那么,创建类就可以有两种方式了



    # 普通方式
    class Foo(object):
        def func(self):
            print("hello UserPython")


    # 特殊方式
    def func(self):
        print("hello %s" % self.name)


    def __init__(self, name, age):  # 构造方法
        self.name = name
        self.age = age


    # 创建了一个type类,然后用type类实例化了一个Foo类,由于Foo本身是一个类,所以Foo又实例化了一个对象foo
    Foo = type(‘Foo‘, (object,), {"func": func, "__init__": __init__})

    foo = Foo("UserPython", 19)

    foo.func()

    print(type(Foo))

    66. 答:5*5*5 ,125个。

    67. 答:反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力。

          Python面向对象中的反射,四个可以实现自省的函数。

          Hasattr()

          Getattr()

          Setattr()

          Delattr()

    68.  答:metaclass是类似创建类的模板,所有的类都是通过他来create的(调用__new__),这使得你可以自由的控制

    创建类的那个过程,实现你所需要的功能。1. 你可以自由的、动态的修改/增加/删除类的或者实例中的方法或者属性

    2. 批量的对某些方法使用decorator,而不需要每次都在方法的上面加入@decorator_func

    3. 当引入第三方库的时候,如果该库某些类需要patch的时候可以用metaclass

    4. 可以用于序列化(参见yaml这个库的实现,我没怎么仔细看)

    5. 提供接口注册,接口格式检查等

    6. 自动委托(auto delegate)

    69. 答:1. 文件导入:import方法

    # 作为python的模块是天然的单例模式

    class My_Singleton(object):

        def foo(self):

            pass

    my_singleton = My_Singleton()

    # to use

    from mysingleton import my_singleton

    my_singleton.foo()

    2. 使用 __new__ 方法:

    --------------------------------(1. # 无法支持多线程:)------------------------------

    class Singleton(object):

        def __init__(self,name):

            self.name = name

        def __new__(cls, *args, **kwargs):

            if not hasattr(Singleton, "instance"):

                Singleton.instance = object.__new__(cls)

            return Singleton.instance

    # to use :

    obj0 = Singleton("alex")

    obj1 = Singleton("alex")

    obj2 = Singleton("alex")

    ----------------------------------(2. # 支持多线程:)---------------------------------

    import threading

    class Singleton(object):

        instance_lock = threading.Lock() # 为线程加互斥锁

        def __init__(self):

            pass

        def __new__(cls, *args, **kwargs):

            if not hasattr(Singleton, "instance"):

                with Singleton.instance_lock:

                    if not hasattr(Singleton, "instance"):

                        Singleton.instance = object.__new__(cls)

                    return Singleton.instance

            return Singleton.instance

    def task():

        obj = Singleton()

        print(obj)

    for i in range(5):

        t = threading.Thread(target=task)

        t.start()

    3. 使用类实现

    --------------------------------(1. # 无法支持多线程:)------------------------------

    import threading

    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

    # to use

    obj = Singleton.instance()

    obj2 = Singleton.instance()

    print(id(obj), id(obj2))

    ----------------------------------(2. # 支持多线程:)---------------------------------

    import time

    import threading

    class Singleton(object):

        _instance_lock = threading.Lock()

        def __init__(self):

            time.sleep(1)

        @classmethod

        def instance(cls, *args, **kwargs):

            if not hasattr(Singleton, "_instance"):

                with Singleton._instance_lock:

                    if not hasattr(Singleton, "_instance"):

                        Singleton._instance = Singleton(*args, **kwargs)

            return Singleton._instance

    # 第一次调用

    def task(arg):

        obj = Singleton.instance()

        print(obj)

    for i in range(10):

        t = threading.Thread(target=task,args=[i,])

        t.start()

    # 第二次调用   

    time.sleep(20)

    obj = Singleton.instance()

    obj2 = Singleton.instance()

    print(id(obj, id(obj2)

    4. 基于metaclass

    --------------------------------------( 方法一 )--------------------------------------

    # 创建对象

    class SingletonType(type):

        def __call__(cls, *args, **kwargs):

            obj = super(SingletonType,cls).__call__(*args, **kwargs)   #type类帮创建__new__和__init__并返回

            return obj

    class Foo(metaclass=SingletonType):

        def __init__(self,name):

            self.name = name

    # to use

    obj = Foo("alex")

    print(id(obj1))

    --------------------------------------( 方法二 )--------------------------------------

    import threading

    class SingletonType(type):

        _instance_lock = threading.Lock()

        def __call__(cls, *args, **kwargs):

            if not hasattr(cls, "_instance"):

                with SingletonType._instance_lock:

                    if not hasattr(cls, "_instance"):

                        cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)

            return cls._instance

    class Foo(metaclass=SingletonType):

        def __init__(self,name):

            self.name = name

    # to use

    obj1 = Foo('name')

    obj2 = Foo('name')

    print(id(obj1),id(obj2))

    70. 答:def waper(func, x,y):

        print( int(x) + int(y) )

        @functools.wapper               # 保留原函数信息

        def inner(*args, **kwargs):

            """blabla的一些注释"""

            res = func(*args, **kwargs)

           return res

        return inner

    @wapper(1,2)

    def func(a):

        return a

    func(123)     

    71.答:try expect

    72. mro即method resolution order,主要用于在多继承时判断调的属性的路径(来自于哪个类)。

    之前查看了很多资料,说mro是基于深度优先搜索算法的。但不完全正确在Python2.3之前是基于此算法,但从Python2.3起应用了新算法:C3算法。

    73.答:介绍:

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

    语法:

        isinstance(object, classinfo)

          - object -- 实例对象。

          - classinfo -- 可以是直接或间接类名、基本类型或者由它们组成的元组。

    返回值:

        如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。。

    应用示例:

        >>>a = 2

        >>> isinstance (a,int)

        True

        >>> isinstance (a,str)

        False

        >>> isinstance (a,(str,int,list))    # 是元组中的一个返回 True

    True

    74.答:

    class Solution(object):
        def twoSum(self, nums, target):
            """
            :type nums: List[int]
            :type target: int
            :rtype: List[int]
            """
            
    if len(nums) <= 1:
                return False
            buff_dict = {}
            for i in range(len(nums)):
                if nums[i] in buff_dict:
                    return [buff_dict[nums[i]], i]
                else:
                    buff_dict[target - nums[i]] = i

    75.  答:

    自定义时间序列化转换器

    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"}

    76. 答:

    import json

    a=json.dumps({"ddf":"你好"},ensure_ascii=False)

    print(a) #{"ddf": "你好"}

    77. 答:

    Python的assert是用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。

    断言应该用于:

    • 防御型的编程
    • 运行时检查程序逻辑
    • 检查约定
    • 程序常量
    • 检查文档

    78.答:with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。

     

    79. 答:PATH = ‘文件夹路径’ 
    1、list_dir = os.listdir(PATH) 
    2、list_dir = next(os.walk(PATH))[1]

     

    80. 答:yield是python中定义为生成器函数,其本质是封装了  __iter__和__next__方法   的迭代器;

    与return返回的区别:return只能返回一次值,函数就终止了,而yield能多次返回值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行;

     

    1. 答:出于编程的喜爱,以及行业本身的前瞻性,创造性,优越性,越是综合的科目越能检验一个人的能力,喜欢这种有挑战的事情。
    2. 答:跟随老师学习,以及自己查询资料,结合实战,进行输入输出以及纠正。
    3. 答:python是强类型加动态语言,自带有丰富的库,可以进行直接调用,无需重复造轮子,缺点是运行相同的程序,速度远慢于其它类型语言。
    4. 答:编译型语言是指在运行前先由编译器将高级语言代码编译为对应机器的cpu汇编指令集,再由汇编器汇编成目标机器码,生成可执行文件,然后最后运行生成的可执行文件。

    解释型在运行时由翻译器将高级语言代码翻译成易于执行的中间代码,并由解释器逐一将该中间代码解释成机器码并执行。

    1. 答:Cpython,由C语言开发,在命令行下运行python就是启动Cpython。

    Ipython,基于Cpython之上的一个交互性解释器,执行方式与Cpython相同。

    PyPy,以执行速度为目标的解释器,采用JIT技术,对python代码进行动态编译,绝大多数代码可以在PyPy下运行。

    Jpython,运行在java平台的python解释器,可以直接把python代码编译成java字节码执行。

    1. 答:8位(bit)=1个字节(byte),位是计算机内部数据存储的最小单位,字节是计算机中数据处理的基本单位,计算机中以字节位单位存储和解释信息,规定一个字节由8个二进制位构成。
    2. 答:8bit = 1byte =1/1024kb = 1/ 1024^2mb = 1/1024^3GB
    3. 答:缩进使用4个空格,或者IDE中以TAB键当做4个空格。

    所有行限制为最多79个字符

    两个空白行围绕顶层函数和类定义

    核心代码应始终使用UTF-8,所有标识符使用纯ascii标识符,并且应尽可能使用英文单词。

    Import接口通常应该分开,导入始终放在文件的顶部,紧跟在任何模块注释和文档字符串之后,模块全局变量和常量之前。

    1. 答:

    v = int('0b1111011', 2)
    print(v)

    v1 = bin(18)
    print(v1)
    v2 = int('011', 8)
    print(v2)
    v3 = oct(30)
    print(v3)
    v4 = int('0x12', 16)
    print(v4)
    print(hex(87))

    10.答:

    a = "10.3.9.12"


    def func(ip):
        Iplist = ip.split(".")  # ['10', '3', '9', '12']
        res = " "
        temp = []
        for i in Iplist:  # <class 'str'>
            i = int(i)  # <class 'int'>
            i = bin(i)[2:]  # <class 'str'>
            temp.append(i.rjust(8, "0"))  # 右对齐,向左填充数据
        res = res.join(temp)
        return res


    b = "".join([" ".join(str(bin(int(i))[2:]).rjust(8, "0") for i in a.split("."))])
    print(func(a))

    11.答:998层

    12.答:1(布尔或:如果x是True,它返回x的值,否则它返回y的计算值。)               
    3(x and y 布尔"与" - :
    如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。)              

          0

          1

          1

          False

    13.答:ascii编码是一个字节,unicode通常是2个字节,GBK则是第一个字节是大于127就固定表示这是一个汉字的开始。Utf-8是每次8个位传输数据,utf-16 就是每次16个位。

    14.      答:机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写,一般从业人员接触不到。

          字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。

    15.答: var = 1 if 条件成立else 2

    16.答:1. 性能

      - Py3.x性能比Py2.5慢15%,但还有很大的提升空间。

    2.编码

      - Py3.X源码文件默认使用utf-8编码

    3. 语法

      - 去除print语句

      - 关键词加入as 和with,还有True,False,None

      - 删除了raw_input,用input代替

      - 新的metaclass语法

    4. 字符串和字节串

      - 字符串只有str一种类型

    5.数据类型

      - 只有一种整型——int

      - 新增了bytes类型

    6.面向对象

      - 容器类和迭代器类被ABCs化,所以cellections模块里的类型比Py2.5多了很多

      - 迭代器的next()方法改名为__next__(),并增加内置函数next(),用以调用迭代器的__next__()方法

    17.答: b, a = a,b

    18.  答:int <= 32 位整数
    long > 32 位整数

    19. 答:两者的区别是xrange返回的是一个可迭代的对象,range返回的则是一个列表. 同时效率更高,更快。

      - 原因是实现的时候使用了 yield(此为python2.x回答,python3已删除xrange)

    20. 答:xreadlines = 返回一个生成器对象,

    readlines =  遍历文件所有行

    21.答:

    //     alert(new Boolean(0));  //false

    //     alert(new Boolean(-0)); // false

    //     alert(new Boolean(null)); // false

    //     alert(new Boolean(NaN)); // false

    //     alert(new Boolean(undefined)); // false

    //     alert(new Boolean("undefined")); // true

    //     alert(new Boolean("")); // false

    //     alert(new Boolean(false)); // false

    //     alert(new Boolean("false")); // true

    22. 答:

          列表:list

        - list.append(obj) # 在列表末尾添加新的对象

        - list.count(obj)  # 统计某个元素在列表中出现的次数

        - list.extend(seq) # 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)

        - list.index(obj)  # 从列表中找出某个值第一个匹配项的索引位置

        - list.insert(index, obj)# 将对象插入列表

        - list.pop(obj=list[-1]) # 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值

        - list.remove(obj) # 移除列表中某个值的第一个匹配项

        - list.reverse()   # 反向列表中元素

        - list.sort([func])# 对原列表进行排序

        - list.clear()     # 清空列表

        - list.copy()      # 复制列表

    字典:dict

        - popitem()    # 随机返回并删除字典中的一对键和值(一般删除末尾对)。

        - key in dict  # 如果键在字典dict里返回true,否则返回false

        - radiansdict.copy()   # 返回一个字典的浅复制

        - radiansdict.keys()   # 以列表返回一个字典所有的键

        - radiansdict.items()  # 以列表返回可遍历的(键, 值) 元组数组

        - radiansdict.clear()  # 删除字典内所有元素

        - radiansdict.values() # 以列表返回字典中的所有值

        - radiansdict.fromkeys()    # 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值

        - radiansdict.update(dict2) # 把字典dict2的键/值对更新到dict里

        - radiansdict.get(key, default=None)        # 返回指定键的值,如果值不在字典中返回default值

        - radiansdict.setdefault(key, default=None) # 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default

        - pop(key[,default])   # 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。否则,返回default值。

    字符串:str

        - upper()      # 转换字符串中的小写字母为大写。

        - title()      # 返回"标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())。

        - lower()      # 转换字符串中所有大写字符为小写。

        - rstrip()     # 删除字符串字符串末尾的空格.

        - lstrip()     # 截掉字符串左边的空格或指定字符。

        - max(str)     # 返回字符串 str 中最大的字母。

        - min(str)     # 返回字符串 str 中最小的字母。

        - join(seq)    # 以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串

         ...

        MySlef

    整数:int

        - bit_length()  # 查询以二进制表示一个数字的值所需的位数

        - int.from_bytes(bytes,byteorder)  # 返回给定字节数组所表示的整数。

        - int.to_bytes(length,byteorder)   # 返回表示整数的字节数组。

    元组:tuple

        - len(tuple) # 计算元组元素个数。

        - max(tuple) # 返回元组中元素最大值。

        - min(tuple) # 返回元组中元素最小值。

        - tuple(seq) # 将列表转换为元组。

    集合:set

        - set1 = set({1, 2, 'barry'}) # 创建集合

        - set2 = {1, 2, 'barry'}      # 创建集合

        - add  # 将元素添加到集合中。如果元素已经存在,这不起作用。

        - del set1  # 删除集合- update # 迭代增加

        - clear  # 删除此集合中的所有元素

        - remove # 删除一个元素

        - pop    # 随机删除一个元素

        - issubset    # 子集

        - issuperset  # 超集

        - union  # 并集。(| 或者 union)

        - difference # 差集。(- 或者 difference)

        - intersection  # 交集。(&  或者 intersection)

        - isdisjoint    # 如果两个集合有一个空交点,则返回True

        - intersection_update  # 用它自己和另一个交集更新一个集合。

        - difference_update  # 删除另一个集合中本集合所拥有的所有元素

        - symmetric_difference  # 反交集。(^ 或者 symmetric_difference)

    浮点:float

        - is_integer # 如果浮点数是整数,则返回True

    collections:Python内建的一个集合模块,提供了许多有用的集合类。

        - Counter     # 是一个简单的计数器,例如,统计字符出现的个数:

        - OrderedDict # 可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key:

        - deque       # 是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

        - defaultdict # 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:

    23. 答:

    my_lambda = lambda arg : arg + 1

    匿名函数主要是和其它函数搭配使用,不需要显示指定函数名。

    24. 答:

    - 1. 不做任何事情,一般用做占位语句。

     - 2. pass是空语句,是为了保持程序结构的完整性。

    25. 答:

    位置参数(positional argument)

    关键词参数(keyword argument)

      - *args表示任何多个无名参数,它本质是一个 tuple ;

      - **kwargs表示关键字参数,它本质上是一个 dict ;

      - 并且同时使用*args和**kwargs时,必须*args参数列要在**kwargs前。

    26. 答:

    - is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。莱布尼茨说过:“世界上没有两片完全相同的叶子”,这个is正是这样的比较,

    比较是不是同一片叶子(即比较的id是否相同,这id类似于人的身份证标识)。

      - == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。这里比较的并非是同一片叶子,可能叶子的种类或者脉络相同就可以了。

           默认会调用对象的 __eq__()方法。

    27.答:浅拷贝:只拷贝父对象,不会拷贝对象的内部的子对象(父对象不同,子对象进行引用,ID相同)深拷贝:拷贝对象及其子对象(父, 子对象不同) 由于深拷贝需要维护一个 memo 用于记录已经拷贝的对象,所以这也是它比较慢的原因

    deepcopy优化版:

    class FiveCardStudInfo(roomai.abstract.AbstractInfo):

        public_state = None

        person_state = None

        def __deepcopy__(self, memodict={}):

            info = FiveCardStudInfo()

            info.public_state = self.public_state.__deepcopy__()

            info.public_state = self.person_state.__deepcopy__()

            return info

    28. 答:引用计数 / 分代回收 / 孤立引用环

    引⽤计数机制的优点:

    1、简单

    2、实时性:⼀旦没有引⽤,内存就直接释放了。不⽤像其他机制等到特定时机。实时性还带来⼀个好处:处理回收内存的时间分摊到了平时。

    引⽤计数机制的缺点:

    1、维护引⽤计数

    2、消耗资源循环引⽤

    list1 = []; list2 =[]

    list1.append(list2); list2.append(list1)

    3、list1与list2相互引⽤,如果不存在其他对象对他们的引用,list1与list2的引用计数也仍然1,所占⽤的内存永远无法被回收,这将是致命的。

     对于如今的强⼤硬件,缺点1尚可接受,但是循环引⽤导致内存泄露,注定python会将引⼊新的回收机制。(分代收集)

    有三种情况会触发垃圾回收:

    1、当 gc 模块的计数器达到阀值的时候,自动回收垃圾

    2、调⽤ gc.collect(),手动回收垃圾

    3、程序退出的时候,python解释器来回收垃圾

    29. 答:可变:

      - list,  - dict

    不可变:

      -str,  - int,  - tuple,  - float,

    30.答 {'k1': [666], 'k2': [666]}

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

    31.答:[2, 2, 2, 2]

    32. 答:map, filter, zip ,isinstance

    33. 答:

    map:遍历序列,对序列中每个元素进行操作,最终获取新的序列。

      - 每个元素增加100:

        - li = [11, 22, 33]

        - new_list = map(lambda a: a + 100, li)

      - 两个列表对应元素相加

        - li = [11, 22, 33]

        - sl = [1, 2, 3, 4]

        - new_list = map(lambda a, b: a + b, li, sl)

    filter:对于序列中的元素进行筛选,最终获取符合条件的序列。

      - 获取列表中大于12的所有元素集合

        - li = [11, 22, 33]

        - new_list = filter(lambda arg: arg > 22, li)

        - # filter第一个参数为空,将获取原来序列

    reduce:对于序列内所有元素进行累计操作。

      - 获取序列所有元素的和

        - li = [11, 22, 33]

        - result = reduce(lambda arg1, arg2: arg1 + arg2, li)

      - # reduce的第一个参数,函数必须要有两个参数

      - # reduce的第二个参数,要循环的序列

      - # reduce的第三个参数,初始值

    34. 答:

    print('
    '.join([' '.join(['%s*%s=%-2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))

    35. 答:

          可通过pip install 模块名来进行联网安装。

          第三方模块,request,django, tornado,flask, redis等等。

    36.      答:time&datetime模块,random模块,os模块,sys模块,shutil模块,json&pickle模块,shelve模块,xml模块,configParser模块,hashlib模块,subprocess模块,logging模块,re模块。

    37. 答:

    Match 从头开始匹配,search匹配包含。

    38. 答:

          贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配

    39. 答:a.    [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]

          b.<generator object <genexpr> at 0x012C4EA0>

    40. 答:a. 1

          b.2

          c.False

          d.True

    41. 答:函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储,所以三次执行的结果就是 [1, 1, 1] ,想每次执行只输出[1] ,默认参数应该设置为None。

    42. 答:list("1,2,3".split(','))

    43. 答:[int(x) for x in ['1','2','3']]

    44.答:列表与列表内包含元祖,以及包含多个元祖。

    45. 答:[i*i for i in range(1,11)]

    46. 答:list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))

    47. 答:1 声明法

    在文件开头声明全局变量variable,

    在具体函数中使用该变量时,需要事先声明 global variable,否则系统将该变量视为局部变量。

    2模块法(推荐)

    把全局变量定义在一个单独的模块中:
    #gl.py
    gl_1 = 'hello'
    gl_2 = 'world'

    在其它模块中使用
    #a.py
    import gl

    def hello_world()
        print gl.gl_1, gl.gl_2

    #b.py
    import gl

    def fun1()
        gl.gl_1 = 'Hello'
        gl.gl_2 = 'World'

    48.答:记录日志,并且日志汇总包含的信息即有正常的程序访问日志,还可能有错误,警告等信息输出,应用场景主要有5个level。

    DEBUG,INFO,WARNING,ERROR,CRITICAL。

    49. 答:

    1. Stack() 创建一个新的空栈

    2. push(item) 添加一个新的元素item到栈顶

    3. pop() 弹出栈顶元素

    4. peek() 返回栈顶元素

    5. is_empty() 判断栈是否为空

    6. size() 返回栈的元素个数

    class Stack(object):

        """栈"""

        def __init__(self):

             self.items = []

        def is_empty(self):

            """判断是否为空"""

            return self.items == []

        def push(self, item):

            """加入元素"""

            self.items.append(item)

        def pop(self):

            """弹出元素"""

            return self.items.pop()

        def peek(self):

            """返回栈顶元素"""

            return self.items[len(self.items)-1]

        def size(self):

            """返回栈的大小"""

            return len(self.items)

    if __name__ == "__main__":

        stack = Stack()

        stack.push("hello")

        stack.push("world")

        stack.push("lcg")

        print stack.size()

        print stack.peek()

        print stack.pop()

        print stack.pop()

        print stack.pop()

    50. 答:

    Python的字符串格式化常用的有三种

      第一种:最方便的

      缺点:需一个个的格式化

    print('hello %s and %s' % ('df', 'another df'))


      第二种:最好用的

      优点:不需要一个个的格式化,可以利用字典的方式,缩短时间

    print('hello %(first)s and %(second)s' % {'first': 'df', 'second': 'another df'})
      第三种:最先进的

        优点:可读性强

    print('hello {first} and {second}'.format(first='df', second='another df'))

    51. 答:

    容器:

       - 是一系列元素的集合,str、list、set、dict、file、sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象。

    可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。

    迭代器:

        - 持有一个内部状态的字段,用于记录下次迭代返回值,它实现了__next__和__iter__方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。

    生成器:

        - 是一种特殊的迭代器,它的返回值不是通过return而是用yield。

    装饰器

    - 在不改变原函数代码的基础上,在执行前后进行定制操作

    52. 答:

    li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


    def search(someone, li):
        l = -1
        h = len(li)

        while l + 1 != h:
            m = int((l + h) / 2)
            if li[m] < someone:
                l = m
            else:
                h = m
        p = h
        if p >= len(li) or li[p] != someone:
            print("元素不存在")
        else:
            str = "元素索引为%d" % p
            print(str)


    search(3, li)  # 元素索引为2

    53. 答:def foo():

        m, n=3, 5

        def bar():

            a=4

            return m+n+a

        return bar

    >>>bar =  foo()

    >>>bar()

    说明:

    bar在foo函数的代码块中定义。我们称bar是foo的内部函数。

    在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。

    简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。

    - 闭包的意义与应用:延迟计算;

    - 闭包的意义:      返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

    #应用领域:延迟计算(原来我们是传参,现在我们是包起来)

    装饰器就是闭包函数的一种应用场景

    54. 答:os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。

    55. 答:使用random模块可以很容易生成随机字符串。

    56. 答:os 模块中使用os.remove()来删除一个文件。

    57. 答:- 简单描述:继承、封装、多态

    - 系统描述:先对代码进行分类:按属性进行划分(file,DB),按功能划分,将同一类方法分为一类。将方法中共同的参数封装到对象中,把共用值封装到对象中。

    面向对象的私有字段:

      - python中一切皆对象

      1. 封装:对数据的,对对象的封装。

      2. 继承:在类的基础上进行二次开发,通过函数super() 或者"基类名.方法名() "的方式实现这一目的的。

      3. 多态:同一个方法处于不同对象中,可以产生不同的结果

    - 多态示例

    # 鸭子模型

      class A:

          def send(self):

              pass

      class B:

          def send(self):

              pass

          def func(arg):

              arg.send()

              obj = B()

      func(obj)

    58. 答:继承指的是类与类之间的关系,是一种“是”什么的关系,继承的功能之一就是解决代码重用问题,python中的继承可分为单继承和多继承。

    59. 答:新式类跟经典类的差别主要是以下几点:

      1. 新式类对象可以直接通过__class__属性获取自身类型:type

      2. 继承搜索的顺序发生了改变,经典类多继承属性搜索顺序:

          - 先深入继承树左侧,再返回,开始找右侧;

          - 新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动。

            ps:(经典类深度优先,新式类广度优先)

      3. 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中。

      4. 新式类增加了__getattribute__方法

    Python 2.x中默认都是经典类,只有显式继承了object才是新式类

    Python 3.x中默认都是新式类,不必显式的继承object

    60. 答:子类继承父类的方法,其继承顺序按照 __mro__来定义

    61.答:

    1. functools模块的引用

    from functools import partial

    2. functools模块的组成

    • partial(func, *args, **keywords)

    通过封装,重新定义已有的函数,如增减参数、设置初始值或改变返回值。
    该函数的返回partial对象,其中包含3个只读属性:

      • partial.func
      • partial.args
      • partial.keywords
      • @total_ordering

    修饰class
    实现多个比较操作方法,如__eq__, __lt__等

    • @lru_cache(maxsize=128, typed=False)

    修饰方法,重新定义已有的函数
    只存在于内存中

    • @singledispatch(default)

    修饰方法
    将函数转换为 single-dispatch generic function

    • @wraps(wrapped_func, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

    调用update_wrapper()方法的简便实现

    • update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
    • reduce(function, iterable[, initializer])
    • cmp_to_key(func)

    Python的functools模块用以为可调用对象(callable objects)定义高阶函数或操作。简单地说,就是基于已有的函数定义新的函数。
    所谓高阶函数,就是以函数作为输入参数,返回也是函数。

    62. 答:- 双下划线:

      1. __getattr__:反射

         应用场景:

           - CBV

           - Django 配置文件

           - wtforms中的Form()实例化中将"_fields中的数据封装到Form类中"

      2. __mro__:定义解析类继承的顺序

         应用场景:wtforms中 FormMeta中继承的优先级

      3. __dict__:用来存储对象属性的一个字典,其键为属性名,值为属性的值

         - __dict__ 与 dir()的区别:

           1. dir()是一个函数,返回值是list

           2. dir用来寻找一个对象的所有属性值,包括__dict__中的属性,__dict__是dir()的子集

      4. __new__ :

         - 当你继承一些不可变的class时(比如int, str, tuple),提供给你一个自定义这些类的实例化过程的途径。

         - 实现自定义 metaclass

         应用场景:

           - wtforms 字段实例化时返回:不是StringField,而是UNboundField

           - rest_framework:many=Ture 中的序列化

           - 单例模式

      5. __call__:作用是使实例能够像函数一样被调用,同时不影响实例本身的生命周期, (__call__()不影响一个实例的构造和析构)

                   但是__call__()可以用来改变实例的内部成员。

         __call__ 与 __init__的区别

         应用场景:

           - FLask 请求的入口app.run()

           - 字段生成标签时:字段.__str__ ==> 字段.__call__ ==> 插件.__call__

      6. __iter__:

         迭代器为什么要一定实现__iter__方法(为什么要返回自身)

         应用场景:wtforms中BaseForm中循环所有字段时自定义了__iter__方法

    63. 答:from types import MethodType,FunctionType

    class func(object):

        def foo(self):

            print(1)

    Fun = func()

    print(type(func.foo))

    >>> <class 'function'>

    print(type(Fun.foo))

    >>> <class 'method'>

    print(isinstance(func.foo,FunctionType))

    >>> True

    print(isinstance(Fun.foo,MethodType))

    >>> True

    通过类去调用函数foo时,不需要传self参数。此时foo为函数

    如果通过对象Fun去调用foo时,对象自动传参self。而foo则是一个方法

    64. 答:一、先是在语法上面的区别:
    1、静态方法不需要传入self参数,类成员方法需要传入代表本类的cls参数;
    2、静态方法是无妨访问实例变量和类变量的,类成员方法无法访问实例变量但是可以访问类变量
    二、使用的区别:
    由于静态方法无法访问类属性,实例属性,相当于一个相对独立的方法,跟类其实并没有什么关系。这样说来,静态方法就是在类的作用域里的函数而已。
     
    65. 答:1.
    __doc__
    描述类的信息


    class Foo(object):
        # 单引号和双引号都可以 
        """这里描述类的信息"""

       
    def func(self):
            pass


    print(Foo.__doc__)


    2.
    __call__
    对象后面加括号,触发执行


    # __call__方法的执行是由对象加括号触发的,即:对象()或者 类()()
    class Foo(object):
        def __call__(self, *args, **kwargs):
            print("running call", args, kwargs)


    foo = Foo()
    foo(1, 2, 3, name="UserPython")

    Foo()(1, 2, 3, name="UserPython")

    3.
    __dict__
    查看类或对象中的所有成员


    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age


    foo = Foo("UserPython", 17)

    print(Foo.__dict__)  # 打印类里的所有属性,不包括实例属性
    print(foo.__dict__)  # 打印所有实例属性,不包括类属性
    显示的结果:

    {‘__weakref__‘: < attribute ‘__weakref__‘ of ‘Foo‘ objects >, ‘__init__‘: < function
    Foo.__init__
    at
    0x0000000000BB0730 >, ‘__dict__‘: < attribute ‘__dict__‘ of ‘Foo‘ objects >, ‘__module__‘: ‘__main__‘, ‘__doc__‘: None}
    {‘name‘: ‘UserPython‘, ‘age‘: 17}

    4.
    __str__
    如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值


    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age

        def __str__(self):
            return "<obj:%s>" % self.name


    foo = Foo("UserPython", 17)

    print(foo)  # >>><obj:UserPython>
    显示的效果为:

    < obj:UserPython >

    5.
    __getitem__ 、 __setitem__ 、__delitem__
    用于索引操作,如字典。分别表示获取、设置、删除数据


    class Foo(object):

        def __getitem__(self, key):
            print("__getitem__", key)

        def __setitem__(self, key, value):
            print("__setitem__", key, value)

        def __delitem__(self, key):
            print("__delitem__", key)


    foo = Foo()
    foo["name"] = "UserPython"  # >>>__setitem__ name UserPython  触发__setitem__
    foo["name"]  # >>>__getitem__ name  触发__getitem__
    del foo["name"]  # >>>__delitem__ name  触发__delitem__


    6.
    __new__ 、__metaclass__


    class Foo(object):

        def __init__(self, name):
            self.name = name


    foo = Foo("UserPython")
    ‘‘‘‘‘
    上述代码中,foo是通过Foo类实例化的对象,其实,不仅foo是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
    如果按照一切事物都是对象的理论:foo对象时通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建。
    ‘‘‘

    print(type(foo))
    print(type(Foo))
    # 所以,foo对象是Foo类的一个实例,Foo类对象是type类的一个实例,即:Foo类对象是通过type类的构造方法创建。那么,创建类就可以有两种方式了



    # 普通方式
    class Foo(object):
        def func(self):
            print("hello UserPython")


    # 特殊方式
    def func(self):
        print("hello %s" % self.name)


    def __init__(self, name, age):  # 构造方法
        self.name = name
        self.age = age


    # 创建了一个type类,然后用type类实例化了一个Foo类,由于Foo本身是一个类,所以Foo又实例化了一个对象foo
    Foo = type(‘Foo‘, (object,), {"func": func, "__init__": __init__})

    foo = Foo("UserPython", 19)

    foo.func()

    print(type(Foo))

    66. 答:5*5*5 ,125个。

    67. 答:反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力。

          Python面向对象中的反射,四个可以实现自省的函数。

          Hasattr()

          Getattr()

          Setattr()

          Delattr()

    68.  答:metaclass是类似创建类的模板,所有的类都是通过他来create的(调用__new__),这使得你可以自由的控制

    创建类的那个过程,实现你所需要的功能。1. 你可以自由的、动态的修改/增加/删除类的或者实例中的方法或者属性

    2. 批量的对某些方法使用decorator,而不需要每次都在方法的上面加入@decorator_func

    3. 当引入第三方库的时候,如果该库某些类需要patch的时候可以用metaclass

    4. 可以用于序列化(参见yaml这个库的实现,我没怎么仔细看)

    5. 提供接口注册,接口格式检查等

    6. 自动委托(auto delegate)

    69. 答:1. 文件导入:import方法

    # 作为python的模块是天然的单例模式

    class My_Singleton(object):

        def foo(self):

            pass

    my_singleton = My_Singleton()

    # to use

    from mysingleton import my_singleton

    my_singleton.foo()

    2. 使用 __new__ 方法:

    --------------------------------(1. # 无法支持多线程:)------------------------------

    class Singleton(object):

        def __init__(self,name):

            self.name = name

        def __new__(cls, *args, **kwargs):

            if not hasattr(Singleton, "instance"):

                Singleton.instance = object.__new__(cls)

            return Singleton.instance

    # to use :

    obj0 = Singleton("alex")

    obj1 = Singleton("alex")

    obj2 = Singleton("alex")

    ----------------------------------(2. # 支持多线程:)---------------------------------

    import threading

    class Singleton(object):

        instance_lock = threading.Lock() # 为线程加互斥锁

        def __init__(self):

            pass

        def __new__(cls, *args, **kwargs):

            if not hasattr(Singleton, "instance"):

                with Singleton.instance_lock:

                    if not hasattr(Singleton, "instance"):

                        Singleton.instance = object.__new__(cls)

                    return Singleton.instance

            return Singleton.instance

    def task():

        obj = Singleton()

        print(obj)

    for i in range(5):

        t = threading.Thread(target=task)

        t.start()

    3. 使用类实现

    --------------------------------(1. # 无法支持多线程:)------------------------------

    import threading

    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

    # to use

    obj = Singleton.instance()

    obj2 = Singleton.instance()

    print(id(obj), id(obj2))

    ----------------------------------(2. # 支持多线程:)---------------------------------

    import time

    import threading

    class Singleton(object):

        _instance_lock = threading.Lock()

        def __init__(self):

            time.sleep(1)

        @classmethod

        def instance(cls, *args, **kwargs):

            if not hasattr(Singleton, "_instance"):

                with Singleton._instance_lock:

                    if not hasattr(Singleton, "_instance"):

                        Singleton._instance = Singleton(*args, **kwargs)

            return Singleton._instance

    # 第一次调用

    def task(arg):

        obj = Singleton.instance()

        print(obj)

    for i in range(10):

        t = threading.Thread(target=task,args=[i,])

        t.start()

    # 第二次调用   

    time.sleep(20)

    obj = Singleton.instance()

    obj2 = Singleton.instance()

    print(id(obj, id(obj2)

    4. 基于metaclass

    --------------------------------------( 方法一 )--------------------------------------

    # 创建对象

    class SingletonType(type):

        def __call__(cls, *args, **kwargs):

            obj = super(SingletonType,cls).__call__(*args, **kwargs)   #type类帮创建__new__和__init__并返回

            return obj

    class Foo(metaclass=SingletonType):

        def __init__(self,name):

            self.name = name

    # to use

    obj = Foo("alex")

    print(id(obj1))

    --------------------------------------( 方法二 )--------------------------------------

    import threading

    class SingletonType(type):

        _instance_lock = threading.Lock()

        def __call__(cls, *args, **kwargs):

            if not hasattr(cls, "_instance"):

                with SingletonType._instance_lock:

                    if not hasattr(cls, "_instance"):

                        cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)

            return cls._instance

    class Foo(metaclass=SingletonType):

        def __init__(self,name):

            self.name = name

    # to use

    obj1 = Foo('name')

    obj2 = Foo('name')

    print(id(obj1),id(obj2))

    70. 答:def waper(func, x,y):

        print( int(x) + int(y) )

        @functools.wapper               # 保留原函数信息

        def inner(*args, **kwargs):

            """blabla的一些注释"""

            res = func(*args, **kwargs)

           return res

        return inner

    @wapper(1,2)

    def func(a):

        return a

    func(123)     

    71.答:try expect

    72. mro即method resolution order,主要用于在多继承时判断调的属性的路径(来自于哪个类)。

    之前查看了很多资料,说mro是基于深度优先搜索算法的。但不完全正确在Python2.3之前是基于此算法,但从Python2.3起应用了新算法:C3算法。

    73.答:介绍:

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

    语法:

        isinstance(object, classinfo)

          - object -- 实例对象。

          - classinfo -- 可以是直接或间接类名、基本类型或者由它们组成的元组。

    返回值:

        如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。。

    应用示例:

        >>>a = 2

        >>> isinstance (a,int)

        True

        >>> isinstance (a,str)

        False

        >>> isinstance (a,(str,int,list))    # 是元组中的一个返回 True

    True

    74.答:

    class Solution(object):
        def twoSum(self, nums, target):
            """
            :type nums: List[int]
            :type target: int
            :rtype: List[int]
            """
            
    if len(nums) <= 1:
                return False
            buff_dict = {}
            for i in range(len(nums)):
                if nums[i] in buff_dict:
                    return [buff_dict[nums[i]], i]
                else:
                    buff_dict[target - nums[i]] = i

    75.  答:

    自定义时间序列化转换器

    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"}

    76. 答:

    import json

    a=json.dumps({"ddf":"你好"},ensure_ascii=False)

    print(a) #{"ddf": "你好"}

    77. 答:

    Python的assert是用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。

    断言应该用于:

    • 防御型的编程
    • 运行时检查程序逻辑
    • 检查约定
    • 程序常量
    • 检查文档

    78.答:with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。

     

    79. 答:PATH = ‘文件夹路径’ 
    1、list_dir = os.listdir(PATH) 
    2、list_dir = next(os.walk(PATH))[1]

     

    80. 答:yield是python中定义为生成器函数,其本质是封装了  __iter__和__next__方法   的迭代器;

    与return返回的区别:return只能返回一次值,函数就终止了,而yield能多次返回值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行;

  • 相关阅读:
    套接字IO超时设置和使用select实现超时管理
    登录页面2
    tornado后台小框架
    form表单,登录用户,密码,按钮,提交、重置
    图标,空格,大小尖括号,段落,换行,标题,div白板,span白板
    html中head示例
    centos7中mysql不能输入中文问题的解决
    ORM多对多的实现
    多外键关联
    ORM外键关联
  • 原文地址:https://www.cnblogs.com/fengkun125/p/9428406.html
Copyright © 2020-2023  润新知