python常见知识

python常见面试题

1.python中可变对象和不可变对象:

可变对象:list dict set

不可变对象:int float bool string tuple

文章链接: https://www.jianshu.com/p/c5582e23b26c — 仔细看

2.python的垃圾回收机制:

文章链接: https://www.cnblogs.com/kumata/p/9099134.html

或者看我自己的博客

3.如何判断单链表中是否有环和找出环的出口:

文章链接: https://blog.csdn.net/yangnianjinxin/article/details/79025768

4.十大排序算法:必须掌握

文章链接: https://blog.csdn.net/qq_42166308/article/details/103356606

5.闭包和装饰器(面向切面编程AOP)实现与区别:

装饰器本质上是一个Python函数,它可以让其它函数在不作任何变动的情况下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景。比如:插入日志、性能测试、事务处理、缓存、权限校验等。有了装饰器我们就可以抽离出大量的与函数功能无关的雷同代码进行重用。

视频链接: https://www.bilibili.com/video/av18586448?from=search&seid=10638981423280212097

6.*args和**kwargs的理解:

文章链接: https://blog.csdn.net/leviopku/article/details/83580138

7.python伪线程解释:

文章链接: https://blog.csdn.net/G_SANGSK/article/details/80867629

8.一行代码实现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)))

10.深浅拷贝原理

import copy
a = [1, 2, 3, 4, ['a', 'b']]  #原始对象

b = a  #赋值,传对象的引用
c = copy.copy(a)  #对象拷贝,浅拷贝
d = copy.deepcopy(a)  #对象拷贝,深拷贝

a.append(5)  #修改对象a
a[4].append('c')  #修改对象a中的['a', 'b']数组对象

print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d

输出结果:
a =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c =  [1, 2, 3, 4, ['a', 'b', 'c']]
d =  [1, 2, 3, 4, ['a', 'b']]

11.python中的新式继承(C3算法),菱形继承 自己找答案

新式类是采用广度优先搜索,旧式类采用深度优先搜索。

12.生成器、迭代器: https://www.runoob.com/python3/python3-iterator-generator.html

13.一行代码实现1-100的加和

sun(range(1,101))

14.字典如何删除和合并两个字典:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aetKMR7v-1584576197094)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1577689875331.png)]

15.python中datetime内置函数和pandas中datetime的相关知识:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yewGs1Rs-1584576197096)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1577696916198.png)]

https://www.cnblogs.com/nxf-rabbit75/p/10660317.html

16…现有字典 d= {‘a’:24,‘g’:52,‘i’:12,‘k’:33}请按value值进行排序?

sorted(d.items(),key=lambda x :x[1])

17.将字符串 “k:1 |k1:2|k2:3|k3:4”,处理成字典 {k:1,k1:2,…}

str1 = "k:1|k1:2|k2:3|k3:4"
#第一种
def str2dict(str1):
    dict1 = {}
    for iterms in str1.split('|'):
        key,value = iterms.split(':')
        dict1[key] = value
    return dict1

#第二种 重点!!!  t.split(':'),加了逗号就可以 相当于解包以为求出来需要[]取出,这里直接就可以加逗号解包
print({k:int(v) for t in str1.split('|') for k,v in (t.split(':'),)})

18.请按alist中元素的age由大到小排序

alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}]
def sort_by_age(list1):
    return sorted(alist,key=lambda x:x['age'],reverse=True)

19.什么是单例模式?python如何实现单例模式?请写出两种实现方式?

https://www.cnblogs.com/huchong/p/8244279.html

第一种方法:使用装饰器

def singleton(cls):
    instances = {}
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return wrapper
    
    
@singleton
class Foo(object):
    pass
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)  # True

第二种方法:使用基类 New 是真正创建实例对象的方法,所以重写基类的new 方法,以此保证创建对象的时候只生成一个实例

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
    
    
class Foo(Singleton):
    pass

foo1 = Foo()
foo2 = Foo()

print(foo1 is foo2)  # True

第三种方法:元类,元类是用于创建类对象的类,类对象创建实例对象时一定要调用call方法,因此在调用call时候保证始终只创建一个实例即可,type是python的元类

class Singleton(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instance


# Python2
class Foo(object):
    __metaclass__ = Singleton

# Python3
class Foo(metaclass=Singleton):
    pass

foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)  # True

20.反转一个整数,例如-123 --> -321

class Solution(object):
    def reverse(self,x):
        if -10<x<10:
            return x
        str_x = str(x)
        if str_x[0] !="-":
            str_x = str_x[::-1]
            x = int(str_x)
        else:
            str_x = str_x[1:][::-1]
            x = int(str_x)
            x = -x
        return x if -2147483648<x<2147483647 else 0 #2^31-1
if __name__ == '__main__':
    s = Solution()
    reverse_int = s.reverse(-120)
    print(reverse_int)

21.设计实现遍历目录与子目录,抓取.pyc文件

import os

#os.walk()方法
#参考https://blog.csdn.net/bagboy_taobao_com/article/details/8938126
def get_files(dir,suffix):
    res = []
    for root,dirs,files in os.walk(dir):
        for filename in files:
            name,suf = os.path.splitext(filename) #取出后缀文本
            if suf == suffix:
                res.append(os.path.join(root,filename))

    print(res)

get_files("./",'.pyc')

22.Python中变量的作用域?(变量查找顺序)

函数作用域的LEGB顺序

1.什么是LEGB?

L: local 函数内部作用域

E: enclosing 函数内部与内嵌函数之间

G: global 全局作用域

B: build-in 内置作用

python在函数里面的查找分为4种,称之为LEGB,也正是按照这是顺序来查找的

23.字符串 "123" 转换成 123,不使用内置api,例如 int()

#1.str函数
def get_value(s):
    num = 0
    for i in s:
        for j in range(10):
            if i == str(j):
                num = num * 10 +j
    return num

#2.巧妙利用ord()函数
def get_value(s):
    num = 0
    for i in s:
        num = num * 10 +ord(i) - ord('0')
    return num

#3.使用reduce方法
#参考https://www.runoob.com/python/python-func-reduce.html
from functools import reduce
def get_value(s):
    return reduce(lambda num, i: num * 10 + ord(i) - ord('0'), s, 0)

#这里第三个参数是初始化num=0定义为整数,你可以自己试一试修改这个值
def get_value(s):
    return reduce(lambda num, i: num * 10 + ord(i) - ord('0'), s, 1)
#答案为1123

24. 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。示例:给定nums = [2,7,11,15],target=9 因为 nums[0]+nums[1] = 2+7 =9,所以返回[0,1]

def func1(nums,target):
    for i in range(len(nums)):
        num = target - nums[i]
        if num in nums:
            return [i, nums.index(num,i+1)] #从i+1之后开始找
#这里是让掌握.index()函数
#list.index(x[, start[, end]])
#x-- 查找的对象。
#start-- 可选,查找的起始位置。
#end-- 可选,查找的结束位置。
        

25.统计一个文本中单词频次最高的10个单词?(不懂!!)

# 使用 built-in 的 Counter 里面的 most_common
import re
from collections import Counter

def test2(filepath):
    with open(filepath) as f:
        return list(map(lambda c: c[0], Counter(re.sub("\W+", " ", f.read()).split()).most_common(10)))

26…两个有序列表,l1,l2,对这两个列表进行合并不可使用extend

def loop_merge_sort(l1,l2):
    tmp = []
    while len(l1)>0 and len(l2)>0:
        if l1[0] <l2[0]:
            tmp.append(l1[0])
            del l1[0]
        else:
            tmp.append(l2[0])
            del l2[0]
    while len(l1)>0:
        tmp.append(l1[0])
        del l1[0]
    while len(l2)>0:
        tmp.append(l2[0])
        del l2[0]
    return tmp

27. 让所有奇数都在偶数前面,而且奇数升序排列,偶数降序排序,如字符串’1982376455’,变成’1355798642’

#第一种方法
l1 = sorted([x for x in s if int(x) % 2 == 0],reverse=True)
l2 = sorted([x for x in s if int(x) % 2 != 0])
out = l2 + l1

#第二种方法!!!(重点)
print("".join(sorted(l, key=lambda x: int(x) % 2 == 0 and 20 - int(x) or int(x))))

28.闭包影响

def multi():
    return [lambda x : i*x for i in range(4)]
print([m(3) for m in multi()]) 

#正确答案是[9,9,9,9],而不是[0,3,6,9]产生的原因是Python的闭包的后期绑定导致的,这意味着在闭包中的变量是在内部函数被调用的时候被查找的,因为,最后函数被调用的时候,for循环已经完成, i 的值最后是3,因此每一个返回值的i都是3,所以最后的结果是[9,9,9,9]

29.判断一个数为奇数、偶数

#1.条件  x % 2 == 0

发现新大陆 偶数和1做与运算为0  奇数为1
#2.条件  x & 1 != 0(奇数)   3&1输出1  4&1输出0

30.map filter reduce方法使用:

文章链接: https://www.jianshu.com/p/44981aba7b1c

其中有个发现点:

>>> list1 = [11,22,33]
>>> map(None,list1)
[11, 22, 33]
>>> list1 = [11,22,33]
>>> list2 = [44,55,66]
>>> list3 = [77,88,99]
>>> map(None,list1,list2,list3)
[(11, 44, 77), (22, 55, 88), (33, 66, 99)]

#和zip(list1,list2,list3)使用一样

31.python中静态方法、类方法、实例方法:

文章链接: https://blog.csdn.net/lihao21/article/details/79762681

32.优化 Python 性能:PyPy、Numba 与 Cython,谁才是目前最优秀的 Python 运算解决方案?

文章链接: https://www.zhihu.com/question/24695645

33.Python中如何动态获取和设置对象的属性?(作为了解)

if hasattr(Parent, 'x'):
    print(getattr(Parent, 'x'))
    setattr(Parent, 'x',3)
print(getattr(Parent,'x'))

34…哪些操作会导致Python内存溢出,怎么处理?

文章链接: https://www.cnblogs.com/xybaby/p/7491656.html 很全面,认真看!!

35.函数调用参数的传递方式是值传递还是引用传递?

Python的参数传递有:位置参数、默认参数、可变参数、关键字参数。

函数的传值到底是值传递还是引用传递、要分情况:

不可变参数用值传递:像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象。

可变参数是引用传递:比如像列表,字典这样的对象是通过引用传递、和C语言里面的用指针传递数组很相似,可变对象能在函数内部改变。

36.一句话解决阶乘函数?

reduce(lambda x,y : x*y,range(1,n+1))

37.请用一行代码 实现将1-N 的整数列表以3为单位分组

N =100
print ([[x for x in range(1,100)] [i:i+3] for i in range(0,N,3)])

38…面向对象中怎么实现只读属性?(两种方法)

  1. 将对象私有化,通过共有方法提供一个读取数据的接口

    class person:
        def __init__(self, x):
            self.__age = 10
        def age(self):
            return self.__age
    t = person(22)
    # t.__age =100
    print(t.age())
    
  2. 最好的方法

    class MyCls(object):
        __weight = 50
        
        @property
        def weight(self):
            return self.__weight
    

39.什么是面向对象?

面向对象是相当于面向过程而言的,面向过程语言是一种基于功能分析的,以算法为中心的程序设计方法,而面向对象是一种基于结构分析的,以数据为中心的程序设计思想。在面向对象语言中有一个很重要的东西,叫做类。面向对象有三大特性:封装、继承、多态。

知乎: 把一组数据结构和处理它们的方法组成对象(object), 把相同行为的对象归纳为(class), 通过类的封装(encapsulation)隐藏内部细节, 通过继承(inheritance)实现类的特化(specialization)/泛化(generalization), ,通过多态(polymorphism)实现基于对象类型的动态分派(dynamic dispatch)。

40.a = “abbbccc”,用正则匹配为abccc,不管有多少b,就出现一次?

#思路:不管有多少个b替换成一个

re.sub(r'b+', 'b', a)

#re.sub()补充看这个文章https://blog.csdn.net/lovemianmian/article/details/8867613

41.正则表达式贪婪与非贪婪模式的区别

贪婪模式:
定义:正则表达式去匹配时,会尽量多的匹配符合条件的内容
标识符:+,?,*,{n},{n,},{n,m}
匹配时,如果遇到上述标识符,代表是贪婪匹配,会尽可能多的去匹配内容

非贪婪模式:
定义:正则表达式去匹配时,会尽量少的匹配符合条件的内容 也就是说,一旦发现匹配符合要求,立马就匹配成功,而不会继续匹配下去(除非有g,开启下一组匹配)
标识符:+?,??,*?,{n}?,{n,}?,{n,m}?
可以看到,非贪婪模式的标识符很有规律,就是贪婪模式的标识符后面加上一个?

42.进程总结

进程:程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间片、pid。 创建进程: 首先要导入multiprocessing中的Process: 创建一个Process对象; 创建Process对象时,可以传递参数;

p = Process(target=XXX,args=(tuple,),kwargs={key:value})
#target = XXX 指定的任务函数,不用加(),
#args=(tuple,)kwargs={key:value}给任务函数传递的参数

在初始化Queue()对象时(例如q=Queue(),若在括号中没有指定最大可接受的消息数量,获数量为负值时,那么就代表可接受的消息数量没有上限一直到内存尽头)

Queue.qsize():返回当前队列包含的消息数量

Queue.empty():如果队列为空,返回True,反之False

Queue.full():如果队列满了,返回True,反之False

Queue.get([block[,timeout]]):获取队列中的一条消息,然后将其从队列中移除,

block默认值为True。

如果block使用默认值,且没有设置timeout(单位秒),消息队列如果为空,此时程序将被阻塞(停在读中状态),直到消息队列读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出“Queue.Empty"异常:

Queue.get_nowait()相当于Queue.get(False)

Queue.put(item,[block[,timeout]]):将item消息写入队列,block默认值为True; 如果block使用默认值,且没有设置timeout(单位秒),消息队列如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息队列腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出”Queue.Full"异常 如果block值为False,消息队列如果没有空间可写入,则会立刻抛出"Queue.Full"异常; Queue.put_nowait(item):相当Queue.put(item,False)

from multiprocessing import Process,Queue
import os,time,random
#写数据进程执行的代码:
def write(q):
    for value in ['A','B','C']:
        print("Put %s to queue..."%(value))
        q.put(value)
        time.sleep(random.random())
#读数据进程执行的代码
def read(q):
    while True:
        if not q.empty():
            value = q.get(True)
            print("Get %s from queue."%(value))
            time.sleep(random.random())
        else:
            break
if __name__=='__main__':
    #父进程创建Queue,并传给各个子进程
    q = Queue()
    pw = Process(target=write,args=(q,))
    pr = Process(target=read,args=(q,))
    #启动子进程pw ,写入:
    pw.start()
    #等待pw结束
    pw.join()
    #启动子进程pr,读取:
    pr.start()
    pr.join()
    #pr 进程里是死循环,无法等待其结束,只能强行终止:
    print('所有数据都写入并且读完')

进程池:

from multiprocessing import Pool
import os,time,random

def worker(msg):
    t_start = time.time()
    print("%s 开始执行,进程号为%d"%(msg,os.getpid()))
    # random.random()随机生成0-1之间的浮点数
    time.sleep(random.random()*2)
    t_stop = time.time()
    print(msg,"执行完毕,耗时%0.2f%(t_stop-t_start))

po = Pool(3)#定义一个进程池,最大进程数3
for i in range(0,10):
    po.apply_async(worker,(i,))
print("---start----")
po.close()
po.join()
print("----end----")

如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到如下的错误信息:

RuntimeError: Queue objects should only be shared between processs through inheritance

from multiprocessing import Manager,Pool
import os,time,random
def reader(q):
    print("reader 启动(%s),父进程为(%s)"%(os.getpid(),os.getpid()))
    for i in range(q.qsize()):
        print("reader 从Queue获取到消息:%s"%q.get(True))

def writer(q):
    print("writer 启动(%s),父进程为(%s)"%(os.getpid(),os.getpid()))
    for i ini "itcast":
        q.put(i)
if __name__ == "__main__":
    print("(%s)start"%os.getpid())
    q = Manager().Queue()#使用Manager中的Queue
    po = Pool()
    po.apply_async(wrtier,(q,))
    time.sleep(1)
    po.apply_async(reader,(q,))
    po.close()
    po.join()
    print("(%s)End"%os.getpid())

43.谈谈你对多进程,多线程,以及协程的理解,项目是否用?

这个问题被问的概念相当之大, 进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。

线程: cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。

协程: 是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操中栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

44.多线程共同操作同一个数据互斥锁同步?(线程锁)

import threading
import time
class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
    
        if mutex.acquire(1):
            num +=1
            msg = self.name + 'set num to ' +str(num)
            print(msg)
            mutex.release()
num = 0
mutex = threading.Lock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__=="__main__":
    test()

45.什么是多线程竞争?

线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱,即所谓的线程不安全

那么怎么解决多线程竞争问题?—锁

锁的好处: 确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下的原子操作问题。

锁的坏处: 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了

锁的致命问题: 死锁

46.请介绍一下Python的线程同步?

一、 setDaemon(False) 当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行的最小单位,当设置多线程时,主线程会创建多个子线程,在Python中,默认情况下就是setDaemon(False),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束。

例子

import threading 
import time

def thread():
    time.sleep(2)
    print('---子线程结束---')

def main():
    t1 = threading.Thread(target=thread)
    t1.start()
    print('---主线程--结束')

if __name__ =='__main__':
    main()
#执行结果
---主线程--结束
---子线程结束---

二、 setDaemon(True) 当我们使用setDaemon(True)时,这是子线程为守护线程,主线程一旦执行结束,则全部子线程被强制终止

例子

import threading
import time
def thread():
    time.sleep(2)
    print(---子线程结束---')
def main():
    t1 = threading.Thread(target=thread)
    t1.setDaemon(True)#设置子线程守护主线程
    t1.start()
    print('---主线程结束---')

if __name__ =='__main__':
    main()
#执行结果
---主线程结束--- #只有主线程结束,子线程来不及执行就被强制结束

三、 join(线程同步) join 所完成的工作就是线程同步,即主线程任务结束以后,进入堵塞状态,一直等待所有的子线程结束以后,主线程再终止。

当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序,所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和,简单的来说,就是给每个子线程一个timeou的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。

没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。

例子

import threading
import time

def thread():
    time.sleep(2)
    print('---子线程结束---')

def main():
    t1 = threading.Thread(target=thread)
    t1.setDaemon(True)
    t1.start()
    t1.join(timeout=1)#1 线程同步,主线程堵塞1s 然后主线程结束,子线程继续执行
                        #2 如果不设置timeout参数就等子线程结束主线程再结束
                        #3 如果设置了setDaemon=True和timeout=1主线程等待1s后会强制杀死子线程,然后主线程结束
    print('---主线程结束---')

if __name__=='__main___':
    main()

47.什么是死锁?

死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

原因和解决方案: https://baike.baidu.com/item/%E6%AD%BB%E9%94%81

扩展:GIL锁 全局解释器锁

作用: 限制多线程同时执行,保证同一时间只有一个线程执行,所以cython里的多线程其实是伪多线程!

所以python里常常使用协程技术来代替多线程,协程是一种更轻量级的线程。

进程和线程的切换时由系统决定,而协程由我们程序员自己决定,而模块gevent下切换是遇到了耗时操作时才会切换

三者的关系:进程里有线程,线程里有协程。

48.说说下面几个概念:同步,异步,阻塞,非阻塞?

同步: 多个任务之间有先后顺序执行,一个执行完下个才能执行。

异步: 多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调!

阻塞: 如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。

非阻塞: 如果不会卡住,可以继续执行,就是说非阻塞的。

同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。

49.python中进程与线程的使用场景?

多进程适合在CPU密集操作(cpu操作指令比较多,如位多的的浮点运算)。

多线程适合在IO密性型操作(读写数据操作比多的的,比如爬虫)

50.线程是并发还是并行,进程是并发还是并行?

并行: 同一时刻多个任务同时在运行

并发:不会在同一时刻同时运行,存在交替执行的情况。

实现并行的库有:multiprocessing

实现并发的库有: threading

程序需要执行较多的读写、请求和回复任务的需要大量的IO操作,IO密集型操作使用并发更好。

CPU运算量大的程序,使用并行会更好

所以:线程是并发,进程是并行;

进程之间互相独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。

51.数据库三范式: https://www.jianshu.com/p/3e97c2a1687b 详细解释

第一范式:要求有主键,并且要求每一个字段原子性不可再分
第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖
第三范式:所有非主键字段和主键字段之间不能产生传递依赖

52.MySql视图知识

文章链接: https://blog.csdn.net/moxigandashu/article/details/63254901

了解:视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的sql操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。

视图不能被索引,也不能有关联的触发器或默认值,如果视图本身内有order by则对视图再次order by将被覆盖。

创建视图: create view xxx as xxxxxx

对于某些视图比如未使用联结子查询分组聚集函数Distinct Union等,是可以对其更新的,对视图的更新将对基表进行更新;但是视图主要用于简化检索,保护数据,并不用于更新,而且大部分视图都不可以更新。

53.数据库优化的思路

文章链接:https://blog.csdn.net/qq_36145093/article/details/88327148

54…存储过程与触发器的区别

文章链接: https://www.cnblogs.com/LILi666/p/10930309.html

55.Redis常见知识:(了解+自己总结的redis知识)

文章链接: https://www.cnblogs.com/jasontec/p/9699242.html

56.青蛙跳台阶问题

一只青蛙要跳上n层高的台阶,一次能跳一级,也可以跳两级,请问这只青蛙有多少种跳上这个n层台阶的方法?

方法1:递归

设青蛙跳上n级台阶有f(n)种方法,把这n种方法分为两大类,第一种最后一次跳了一级台阶,这类共有f(n-1)种,第二种最后一次跳了两级台阶,这种方法共有f(n-2)种,则得出递推公式f(n)=f(n-1) + f(n-2),显然f(1)=1,f(2)=2,这种方法虽然代码简单,但效率低,会超出时间上限

class Solution:
    def climbStairs(self,n):
        if n ==1:
            return 1
        elif n==2:
            return 2
        else:
            return self.climbStairs(n-1) + self.climbStairs(n-2)

方法2:用循环来代替递归

class Solution:
    def climbStairs(self,n):
        if n==1 or n==2:
            return n
        a,b,c = 1,2,3
        for i in range(3,n+1):
            c = a+b
            a = b
            b = c
        return c

57.序列化和反序列化:

文章链接: https://www.cnblogs.com/yyds/p/6563608.html

注意:

Python dict中的非字符串key被转换成JSON字符串时都会被转换为小写字符串;

Python中的tuple,在序列化时会被转换为array,但是反序列化时,array会被转化为list;

由以上两点可知,当Python对象中包含tuple数据或者包含dict,且dict中存在非字符串的key时,反序列化后得到的结果与原来的Python对象是不一致的;
对于Python内置的数据类型(如:str, unicode, int, float, bool, None, list, tuple, dict)

json模块可以直接进行序列化/反序列化处理;对于自定义类的对象进行序列化和反序列化时,需要我们自己定义一个方法来完成定义object和dict之间进行转化

58.python二分法查找:

#第一种 非递归方法
def binary_search(alist,item):
    n = len(alist)
    start = 0
    end = len(alist) - 1
    while start <= end:
        mid = (start + end) // 2
        if alist[mid] == item:
            return mid
        elif item < alist[mid]:
            end = mid - 1
        else:
            start = mid + 1
    return False

print(binary_search([1,2,3,34,56,57,78,87],3))
#第二种  递归方法
def binary_search(alist,item):
    n = len(alist)
    if 0 == n:
        return False
    mid = n // 2
    if alist[mid] == item:
        return mid
    elif item < alist[mid]:
        return binary_search(alist[:mid], item)
    else:
        return binary_search(alist[mid + 1:], item)
    
print(binary_search([1,2,3,34,56,57,78,87],3))

59.python实现Stack、Queue、链表、树:

一、实现栈的方法:

class Stack():
    def __init__(self, size):
        self.size = size
        self.stack = []
        self.top = -1

    def push(self, x):
        if self.isfull():
            raise Exception('stack is full')
        else:
            self.stack.append(x)
            self.top += 1

    def pop(self):
        if self.isempty():
            raise Exception('stack is empty')
        else:
            self.top -= 1
            self.stack.pop()

    def isfull(self):
        return self.top + 1 == self.size

    def isempty(self):
        return self.top == -1

    def showstack(self):
        print(self.stack)


s = Stack(10)
for i in range(6):
    s.push(i)
s.showstack()
for i in range(3):
    s.pop()
s.showstack()

二、实现单向队列:【day22数据结构视频!!】

class Queue():
    def __init__(self, size):
        self.size = size
        self.queue = []
        self.rear = -1
        self.front = -1

    def enqueue(self, ele):
        if self.isfull():
            raise Exception('queue is full')
        else:
            self.queue.append(ele)
            self.rear += 1

    def denqueue(self):
        if self.isempty():
            raise Exception('queue is empty')
        else:
            self.queue.pop(0)
            self.front += 1

    def isfull(self):
        return self.rear - self.front + 1 == self.size

    def isempty(self):
        return self.front == self.rear

    def showenqueue(self):
        print(self.queue)


queue = Queue(10)
for i in range(5):
    queue.enqueue(i)
queue.showenqueue()
for i in range(3):
    queue.denqueue()
queue.showenqueue()

三、实现双向队列:

'''
双端队列:(deque,全名double-ended queue),是一种具有队列和栈的性质的数据结构。
双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。双端队列可以在队列任意一端入队和出队。
'''
from collections import deque

class Deque:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def add_front(self, item):
        # 从头部添加
        self.items.insert(0, item)

    def add_rear(self, item):
        self.items.append(item)

    def remove_front(self):
        return self.items.pop(0)

    def remove_rear(self):
        return self.items.pop()

    def size(self):
        return len(self.items)

    def print_all(self):
        for item in self.items:
            print(item)


if __name__ == '__main__':
    dq = Deque()
    dq.add_front(8)
    dq.add_front(9)
    dq.add_front(0)

    dq.print_all()

    dq.add_rear(6)
    dq.print_all()

    print('-----------remove---------')
    dq.remove_front()

    dq.print_all()

四、实现单链表 【对应day21数据结构视频】

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

    def __str__(self):
        return str(self.data)

class SingleList:
    def __init__(self, node=None):
        self._head = node

    def isEmpty(self):
        return self._head == None

    def append(self, item):
        # 尾部添加
        node = Node(item)
        if self.isEmpty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node

    # 求长度
    def len(self):
        cur = self._head
        count = 0

        while cur != None:
            count += 1
            cur = cur.next

        return count

    # 遍历
    def print_all(self):
        cur = self._head
        while cur != None:
            print(cur)
            cur = cur.next

    def pop(self, index):
        if index < 0 or index >= self.len():
            raise IndexError('index Error')
        if index == 0:
            self._head = self._head.next
        else:
            cur = self._head
            # 找到当前下标的前一个元素!!
            while index - 1:
                cur = cur.next
                index -= 1
            # 修改的next的指向位置
            cur.next = cur.next.next

    def insert(self, index, item):
        if index < 0 or index >= self.len():
            raise IndexError('index Error')
        if isinstance(item, Node):
            raise TypeError('不能是Node类型')
        else:
            node = Node(item)

        if index == 0:
            node.next = self._head
            self._head = node
        else:
            cur = self._head

            while index - 1:
                cur = cur.next
                index -= 1

            node.next = cur.next
            cur.next = node

    def update(self, index, new_item):
        pass

    def remove(self, item):
        pass


if __name__ == '__main__':
    slist = SingleList()
    print(slist.isEmpty())  # True
    print(slist.len())

    slist.append(5)
    print(slist.isEmpty())  # False
    print(slist.len())  # 1

    slist.append(8)
    slist.append(6)
    slist.append(3)
    slist.append(1)
    print(slist.isEmpty())  # True
    print(slist.len())
    print('---------------------')
    slist.print_all()

    print('----------pop-------------')
    slist.pop(2)
    slist.print_all()

    print('--------insert-------')
    slist.insert(1, 19)
    slist.print_all()

五、实现双向链表

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
        self.prev = None

    def __str__(self):
        return str(self.data)


class DoubleList:
    def __init__(self):
        self._head = None

    def isEmpty(self):
        return self._head == None

    def append(self, item):
        # 尾部添加
        node = Node(item)
        if self.isEmpty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node

        # 求长度

    def add(self, item):
        node = Node(item)
        if self.isEmpty():
            self._head = node
        else:
            node.next = self._head
            self._head.prev = node
            self._head = node

    def len(self):
        cur = self._head
        count = 0

        while cur != None:
            count += 1
            cur = cur.next

        return count

    def print_all(self):
        cur = self._head
        while cur != None:
            print(cur)
            cur = cur.next

    def insert(self, index, item):
        if index < 0 or index >= self.len():
            raise IndexError('Index Error')
        if index == 0:
            node = Node(item)
            node.next = self._head
            self._head.prev = node
            self._head = node
        else:
            node = Node(item)
            cur = self._head
            # 也是找到前一个元素
            while index - 1:
                cur = cur.next
                index -= 1

            # 下面这四句顺序无所谓
            node.prev = cur
            node.next = cur.next
            # 因为是双向的,所以反方向也得写
            cur.next.prev = node
            cur.next = node

    def remove(self, item):
        if self.isEmpty():
            raise ValueError('item not in doublelinklist')
        else:
            cur = self._head
            if cur.data == item:
                # 删除的是头结点
                if cur.next == None:
                    # 只有头部节点
                    self._head = None
                else:
                    # 还有其他节点
                    cur.next.prev = None
                    self._head = cur.next
            else:
                while cur != None:
                    if cur.data == item:
                        cur.prev.next = cur.next
                        cur.next.prev = cur.prev
                        break
                    cur = cur.next

    def update(self, index, item):
        pass


if __name__ == '__main__':
    dlist = DoubleList()

    print(dlist.len())
    print(dlist.isEmpty())

    # dlist.append(6)
    # dlist.append(9)
    # dlist.append(5)
    # print(dlist.len())
    # print(dlist.isEmpty())
    # dlist.print_all()

    dlist.add(6)
    dlist.add(9)
    dlist.add(5)

    dlist.print_all()

六、实现树结构:

class Node:
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None

class Tree:
    def __init__(self):
        self.root = None

    def add(self, data):
        node = Node(data)
        if self.root is None:
            self.root = node
            return
        queue = [self.root]
        while queue:
            cur = queue.pop(0)
            if cur.lchild is None:
                cur.lchild = node
                return
            else:
                queue.append(cur.lchild)

            if cur.rchild is None:
                cur.rchild = node
                return
            else:
                queue.append(cur.rchild)

    # 广度优先
    def breadth_travel(self):
        if self.root is None:
            return
        queue = [self.root]
        while queue:
            cur = queue.pop(0)
            print(cur.data, sep=' ', end="")
            if cur.lchild is not None:
                queue.append(cur.lchild)
            if cur.rchild is not None:
                queue.append(cur.rchild)

    # 先序遍历
    def front_travel(self, node):
        if node is None:
            return
        print(node.data, end=' ')
        self.front_travel(node.lchild)
        self.front_travel(node.rchild)

    # 中序遍历
    def mid_travel(self, node):
        if node is None:
            return
        self.mid_travel(node.lchild)
        print(node.data, end=' ')
        self.mid_travel(node.rchild)

    def rear_travel(self, node):
        if node is None:
            return
        self.rear_travel(node.lchild)
        self.rear_travel(node.rchild)
        print(node.data, end=' ')


if __name__ == '__main__':
    t = Tree()
    for i in range(10):
        t.add(i)

    t.breadth_travel()
    print()
    # 执行先序遍历
    t.front_travel(t.root)
    print()
    # 中序遍历
    t.mid_travel(t.root)
    print()
    # 后序遍历
    t.rear_travel(t.root)

59.单链表翻转:没有很懂!!

文章链接: https://blog.csdn.net/u011452172/article/details/78127836

60.Python自省

这个也是python彪悍的特性.

自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.比如type(),dir(),getattr(),hasattr(),isinstance().

61. 迭代器和生成器重要面试题:

这里有个关于生成器的创建问题面试官有考: 问: 将列表生成式中[]改成() 之后数据结构是否改变? 答案:是,从列表变为生成器

>>> L = [x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000028F8B774200>

通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含百万元素的列表,不仅是占用很大的内存空间,如:我们只需要访问前面的几个元素,后面大部分元素所占的空间都是浪费的。因此,没有必要创建完整的列表(节省大量内存空间)。在Python中,我们可以采用生成器:边循环,边计算的机制—>generator

62.*号巧妙使用:还可以看cookbook第一节

>>> def print_three_things(a, b, c):
...     print 'a = {0}, b = {1}, c = {2}'.format(a,b,c)
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)

a = aardvark, b = baboon, c = cat

63.鸭子类型: “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

文章链接: https://blog.csdn.net/handsomekang/article/details/40270009

class Duck:
    def quack(self):
        print "这鸭子正在嘎嘎叫"

    def feathers(self):
        print "这鸭子拥有白色和灰色的羽毛"


class Person:
    def quack(self):
        print "这人正在模仿鸭子"

    def feathers(self):
        print "这人在地上拿起1根羽毛然后给其他人看"


def in_the_forest(duck):
    duck.quack()
    duck.feathers()


def game():
    donald = Duck()
    john = Person()
    in_the_forest(donald)
    in_the_forest(john)


game()

64.为什么 Python 不支持函数重载?其他语言大部分都支持的?

文章链接: https://www.zhihu.com/question/20053359

65. IO多路复用的机制 selectpoll、epoll之间的区别(搜狗面试)

文章链接: https://www.cnblogs.com/aspirant/p/9166944.html

66. 腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在40亿个数当中? (可以考虑作为项目经验!!)

文章链接: https://blog.csdn.net/v123411739/article/details/86652806?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

其中还涉及到bitmap算法、hashmap算法。

https://juejin.im/post/5c4fd2af51882525da267385

67.算法:海量日志数据,提取出某日访问百度次数最多的那个IP

文章链接: https://blog.csdn.net/tayanxunhua/article/details/20528389

68.什么是用户画像,一般用户画像的作用是什么?

文章链接: https://www.zhihu.com/question/19853605

69.协同过滤:下面只是参考,自己多查

协同过滤简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐用户感兴趣的信息,个人通过合作的机制给予信息相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,回应不一定局限于特别感兴趣的,特别不感兴趣信息的纪录也相当重要。

协同过滤又可分为评比(rating)或者群体过滤(social filtering)协同过滤以其出色的速度和健壮性,在全球互联网领域炙手可热。

文章链接: https://blog.csdn.net/yimingsilence/article/details/54934302

https://www.jianshu.com/p/5463ab162a58

70.抖音平台的推荐机制: https://www.kuaidou8.com/135

71.数据分析面试总结(经典)

文章链接: https://www.nowcoder.com/discuss/100521?type=2

72.数据分析必备算法 — TOP- K算法

文章链接: https://juejin.im/entry/5c565fb7f265da2d84105958

https://blog.csdn.net/luochoudan/article/details/53736752

73.动态规划:讲的特别好(这个老师有很多讲),进入个人空间里面还有深度遍历和广度遍历,这个老师的算法都要看,别偷懒

视频链接: https://space.bilibili.com/24014925/channel/detail?cid=44716

74.excel中的vlookup函数,输出后先右拉再下拉。—参考本文件夹下的vlookup.xlsx

75、空数据如何补充?看这篇博客 https://blog.csdn.net/Soft_Po/article/details/89302887

23411739/article/details/86652806?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

其中还涉及到bitmap算法、hashmap算法。

https://juejin.im/post/5c4fd2af51882525da267385

67.算法:海量日志数据,提取出某日访问百度次数最多的那个IP

文章链接: https://blog.csdn.net/tayanxunhua/article/details/20528389

68.什么是用户画像,一般用户画像的作用是什么?

文章链接: https://www.zhihu.com/question/19853605

69.协同过滤:下面只是参考,自己多查

协同过滤简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐用户感兴趣的信息,个人通过合作的机制给予信息相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,回应不一定局限于特别感兴趣的,特别不感兴趣信息的纪录也相当重要。

协同过滤又可分为评比(rating)或者群体过滤(social filtering)协同过滤以其出色的速度和健壮性,在全球互联网领域炙手可热。

文章链接: https://blog.csdn.net/yimingsilence/article/details/54934302

https://www.jianshu.com/p/5463ab162a58

70.抖音平台的推荐机制: https://www.kuaidou8.com/135

71.数据分析面试总结(经典)

文章链接: https://www.nowcoder.com/discuss/100521?type=2

72.数据分析必备算法 — TOP- K算法

文章链接: https://juejin.im/entry/5c565fb7f265da2d84105958

https://blog.csdn.net/luochoudan/article/details/53736752

73.动态规划:讲的特别好(这个老师有很多讲),进入个人空间里面还有深度遍历和广度遍历,这个老师的算法都要看,别偷懒

视频链接: https://space.bilibili.com/24014925/channel/detail?cid=44716

74.excel中的vlookup函数,输出后先右拉再下拉。—参考本文件夹下的vlookup.xlsx

75、空数据如何补充?看这篇博客 https://blog.csdn.net/Soft_Po/article/details/89302887

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wX75QSNX-1584576197101)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1583136797062.png)]

你可能感兴趣的:(python常见知识)