面试题

  1. http和https的区别?

    HTTP是一种常用的协议,但在数据传输过程中不加密,安全性较低。而HTTPS通过加密数据传输和身份验证,提供了更高的安全性。对于涉及敏感信息(例如个人身份信息、信用卡数据等)的网站和应用程序,使用HTTPS是必要的。
    
  2. django请求的生命周期?

    请求到达:当用户在浏览器中输入URL并发送请求时,Web服务器接收到请求并将其转发给Django应用程序。
    中间件处理:在视图函数执行之前,Django的中间件会对请求进行一些预处理操作。中间件可以执行各种任务,如身份验证、请求日志记录、请求处理等。
    URL路由:Django的URL路由系统将根据请求的URL路径来匹配相应的视图函数或处理程序。它会检查urls.py文件中定义的URL模式,并将请求分发到匹配的处理程序。
    视图函数执行:匹配的视图函数将被执行,它会接收请求对象作为参数,并根据业务逻辑进行处理。视图函数可能会访问数据库、调用其他函数、生成响应等。
    模板渲染:如果视图函数需要将数据呈现到模板中,它将从数据库或其他数据源中检索数据,并将数据传递给相应的模板。模板引擎将使用数据来生成最终的HTML响应。
    响应生成:视图函数返回一个HTTP响应对象,该对象包含状态码、响应头和响应体。响应可以是HTML页面、JSON数据、文件下载等。
    中间件处理:在响应发送到客户端之前,Django的中间件可以对响应进行一些后处理操作。它们可以修改响应内容、添加响应头、设置Cookie等。
    响应发送:最终,HTTP响应将通过Web服务器发送回客户端,客户端(浏览器)会接收并解析响应,将其渲染为可视化的内容。
    
  3. 简述django中间件及其应用场景

    Django中间件是一个可插拔的组件,用于在处理请求和响应的过程中执行预处理和后处理操作。
    中间件可以在请求到达视图函数之前和响应发送给客户端之前进行干预和处理。它们可以执行各种任务,例如身份验证、日志记录、缓存、异常处理、性能优化等。
    
  4. 简述django FBV和CBV

    FBV是基于函数编程,CBV是基于类编程,本质上也是FBV编程,在Djanog中使用CBV,则需要继承View类,在路由中指定as_view函数,返回的还是一个函数
    在DRF中的使用的就是CBV编程
    
  5. django中的F和Q函数的作用

    在Django ORM中,F是一个用于数据库查询的特殊对象,用于执行基于数据库字段之间的比较和操作
    在Django ORM中,Q对象是用于构建复杂查询条件的工具,它提供了逻辑操作符(如AND、OR、NOT)来组合多个查询条件。
    
  6. django的模板中filter、simple_tag、inclusion_tag的区别

    在Django模板中,filter、simple_tag和inclusion_tag都是用于自定义模板标签和过滤器的方法,但它们在功能和使用方式上有一些区别:
    
    Filter(过滤器):参数:1-2个
    过滤器是用于在模板中处理变量的函数,可以对变量进行一些简单的处理或转换。
    过滤器可以通过管道(|)将其应用于变量,以修改变量的输出结果。
    过滤器通常用于对字符串、日期、数字等数据进行格式化或转换。
    Django提供了一些内置的过滤器,例如date、lower、upper等,同时也支持自定义过滤器。
    
    Simple Tag(简单标签):参数:无限制
    简单标签是一种自定义模板标签,它是一个Python函数,接受参数并生成一些输出。
    简单标签可以在模板中以类似于函数调用的方式使用,并将标签的返回值插入到模板中。
    简单标签通常用于执行一些简单的逻辑操作,生成动态内容,并将其嵌入到模板中。
    
    Inclusion Tag(包含标签):参数:无限制
    包含标签也是一种自定义模板标签,它是一个Python函数,用于生成包含其他模板的片段。
    包含标签接受参数,并使用指定的参数渲染其他模板。
    包含标签通常用于将公共的模板片段(如导航栏、页脚等)封装为可重用的组件,并在多个模板中使用。
    
  7. select_related和prefetch_related的区别和使用场景?

    "select_related" 和 "prefetch_related" 都是 Django ORM 提供的用于优化数据库查询的方法,但它们的作用和使用场景略有不同。
    
    1. **select_related**:
       - 作用:通过使用 "select_related" 方法,Django 会在查询时使用 SQL 的 JOIN 操作,将外键关联的对象一并获取,从而在单次查询中获取所有相关数据。
       - 使用场景:适用于 ForeignKey 和 OneToOneField 等外键关联的查询。当你需要在一个查询中获取主对象和关联对象的数据时,可以使用 "select_related" 来避免多次数据库查询,提高性能。
       - 注意事项:"select_related" 适合于外键关联,但如果涉及多对多关系或反向关联,性能可能不如 "prefetch_related",因为 "select_related" 会产生多个 JOIN 操作,可能导致性能下降。
    
    2. **prefetch_related**:
       - 作用:"prefetch_related" 用于优化查询涉及多对多关系和反向关联(例如 ManyToManyField 和 Reverse ForeignKey)的情况。它会在单次查询中获取所有相关数据,避免了 N+1 查询问题。
       - 使用场景:适用于优化多对多关系和反向关联的查询。当你需要在查询中获取主对象及其关联对象的数据,并且涉及多对多关系或反向关联时,可以使用 "prefetch_related"。
       - 注意事项:"prefetch_related" 可以显著提高性能,但需要注意不要过度使用,以免导致不必要的资源消耗。
    
    综合使用场景和注意事项,可以根据查询需求选择适当的方法:
    
    - 如果查询涉及到外键关联,并且你需要获取主对象和关联对象的数据,可以考虑使用 "select_related"。
    - 如果查询涉及到多对多关系或反向关联,并且你需要获取主对象及其关联对象的数据,可以考虑使用 "prefetch_related"。
    
    最佳实践是根据数据模型和具体查询需求来选择使用哪种方法,以达到最佳性能和资源利用。
    
  8. 简述python中的垃圾回收机制

  9. 简述python的元类

  10. 简述python中如何实现单例模式

  11. 简述python中的多线程,多进程和协程

  12. 简述Python中的GIL

  13. python中的死锁和如何避免

  14. lambdy函数和普通函数的区别

  15. 简述mysql的事务

  16. 简述mysql的索引

  17. mysql中常见的引擎和主要使用场景

  18. git中如何解决冲突

  19. python实现算法实现代码全排列

    # 使用深度优先
    def permute(nums):
        def dfs(start):
            if start == len(nums):
                result.append(nums[:])
                return
            for i in range(start, len(nums)):
                nums[start], nums[i] = nums[i], nums[start]
                dfs(start + 1)
                nums[start], nums[i] = nums[i], nums[start]  # 恢复原始状态
        
        result = []
        dfs(0)
        return result
    
    # 测试
    nums = [1, 2, 3]
    permutations = permute(nums)
    for perm in permutations:
        print(perm)
    
  20. 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。 示例 1: 输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 示例 2: 输入:nums = [] 输出:[] 示例 3: 输入:nums = [0] 输出:[]

    def threeSum(nums):
        n = len(nums)
        if n < 3:
            return []
    
        nums.sort()
        res = []
    
        for i in range(n-2):
            if i > 0 and nums[i] == nums[i-1]:
                continue
    
            left = i + 1
            right = n - 1
    
            while left < right:
                total = nums[i] + nums[left] + nums[right]
                if total == 0:
                    res.append([nums[i], nums[left], nums[right]])
                    while left < right and nums[left] == nums[left+1]:
                        left += 1
                    while left < right and nums[right] == nums[right-1]:
                        right -= 1
                    left += 1
                    right -= 1
                elif total < 0:
                    left += 1
                else:
                    right -= 1
    
        return res
    
    
  21. 给定一个二维数组arr,数组中的元素都是0或1, 素有相邻元素都为1的为连通区域,找到最大的连通区域

    # 要找到二维数组 arr 中最大的连通区域,可以使用深度优先搜索(DFS)或广度优先搜索(BFS)的算法来解决
    def max_connected_area(arr):
        if not arr:
            return 0
    
        rows = len(arr)
        cols = len(arr[0])
        max_area = 0
    
        def dfs(row, col):
            if row < 0 or row >= rows or col < 0 or col >= cols or arr[row][col] != 1:
                return 0
    
            area = 1
            arr[row][col] = -1  # 标记已访问过的区域为-1
    
            # 递归搜索上下左右四个方向
            area += dfs(row - 1, col)  # 上
            area += dfs(row + 1, col)  # 下
            area += dfs(row, col - 1)  # 左
            area += dfs(row, col + 1)  # 右
    
            return area
    
        for row in range(rows):
            for col in range(cols):
                if arr[row][col] == 1:
                    max_area = max(max_area, dfs(row, col))
    
        return max_area
    
    # 示例用法
    arr = [
        [1, 1, 0, 0, 0],
        [1, 1, 0, 0, 1],
        [0, 0, 1, 1, 0],
        [0, 0, 0, 1, 1],
    ]
    max_area = max_connected_area(arr)
    print(max_area)  # 输出:5
    
    

Python面试题

1、数据库三大范式是什么

第一范式:
	每列都是最小列不可再次分割,如订单列,会存在订单时间,订单地址,所以一般会直接写成两列,而不是一列
第二范式:
	在第一范式的基础上建立起来
    单主键:除主键以外的列都要完全依赖与主键,其他所有列都要和主键有关系
    复合主键:除主键以外的任何列都要完全依赖主键,其他所有列都要同时依赖多个主键,而不是只依赖其中一部分
第三范式:
	在第二范式的基础上建立起来
    表中的非主键列必须和主键直接相关,而不能间接相关,也就是不能传递依赖

2、mysql有哪些索引类型,分别有什么作用

1. 主键索引:
	每个表都会有主键,也会有主键索引,就算不建立也会有,只是你看不见,也用不了。因为mysql是基于主键建立b+树的。主键索引是最快的
2. 辅助索引(普通索引):
	定义的时候自己给字段加上的索引,在Django中是定义字段时加个index=True,通过这个字段查询会提高速度,要是年龄,性别这种变化小的,就别加了,只会浪费时间
    CREATE INDEX index_id ON tb_student(id);
3. 唯一索引(unique):
	不是为了提高访问速度,而是为了避免数据出现重复,虽然也能提高速度
    唯一索引通常使用 UNIQUE 关键字
    CREATE UNIQUE INDEX index_id ON tb_student(id);
4. 组合索引(联合索引):
	django 中:class Meta:
    CREATE INDEX index_name
    ON table_name (column1, column2, column3); 
5. 全文索引-->基本不用-->:
    全文索引主要用来查找文本中的关键字,只能在 CHAR、VARCHAR 或 TEXT 类型的列上创建。
    在 MySQL 中只有 MyISAM 存储引擎支持全文索引。
    全文索引允许在索引列中插入重复值和空值。
    不过对于大容量的数据表,生成全文索引非常消耗时间和硬盘空间。
    创建全文索引使用 FULLTEXT 关键字

3、事务的特性和隔离级别

事务四大特性(ACID)
1. 原子性(Atomicity)
	一次事物中,要么全成功,要不全部回滚
2. 隔离性(Isolation)
	事物之间相互隔离,彼此不受影响,这与事物的隔离性级别密切相关
3. 一致性(Consistency)
	事务执行前后的状态要一致,可理解为数据一致性
4. 持久性(Durable)
	事务完成之后,她对数据的修改是永恒的,即时出现故障也能够正常保持
隔离级别
1. Read uncommitted(读未提交)-ru
	一个事物读到了另一个事务未提交的数据
2. Read committed(读已提交)-rc
	如果设置了这个级别一个事物读不到另一个事务未提交的数据
    写事务提交之前不允许其他事务的读操作
3. Repeatable read(可重复读取)-rr
    在开始读取数据(事务开启)时,不再允许修改操作,这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别
4. Serializable(串行化)
	求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行

4、脏读,不可重复读,幻读 ,mysql5.7以后默认隔离级别是什么?

1. 脏读:
	读到了,其他事务未提交的数据,这些数据可能会回滚,也就是可能不存在,读到了不一定存在的数据就是脏读
2. 不可重复读:
	就是同一个事务内,开始和结束读到的同一批数据不一致
    原因是因为,A事务读了,然后B事务提交了,A事务再次读的时候数据不一致了
3. 幻读:
	读的时候查询没有,写的时候查询又说冲突
默认隔离级别是Repeatable read(可重复读取)-rr
-Read uncommitted(读未提交)-ru:存在脏读,不可重复读,幻读
-Read committed(读已提交)-rc:解决了脏读,但是存在不可重复读和幻读
-Repeatable read(可重复读取)-rr:解决了脏读,不可重复读问题,存在幻读问题
-Serializable(串行化):解决了脏读,不可重复读和幻读问题,牺牲了效率
Oracle仅支持两种隔离级别:
Read Committed:读已提交
Serializable:默认基本为RC  存在不可重复读问题

5、什么是qps,tps,并发量,pv,uv

1. qps:
	每秒查询率--->一台服务器每秒能够响应的查询次数,每秒的响应请求数
    不使用缓存:大约8核16G机器,qps 400多,如果横向扩展,10台8核16g的机器,qps大约4000多
	使用缓存:大约8核16G机器,qps破千没问题
2. tps:
    每秒处理的事务数--->从事务的开始计时,到收到服务器响应结束
3. 并发量:
	系统同时处理的请求数量
	QPS = 并发量 / 平均响应时间
	并发量 = QPS * 平均响应时间
    例如当前系统QPS为1w,每个请求的响应时间都是2s,那么并发量就是2w
4. PV:
	页面访问量,即页面浏览量或点击量,用户每次刷新即被计算一次。可以统计服务一天的访问日志得到
5. UV:
    独立访客,统计1天内访问某站点的用户数。可以统计服务一天的访问日志并根据用户的唯一标识去重得到

-# DAU(日活)
    DAU(Daily Active User),日活跃用户数量。常用于反映网站、app、网游的运营情况。
    DAU通常统计一日(统计日)之内,登录或使用了某个产品的用户数(去除重复登录的用户),与UV概念相似

-# MAU(月活)
    MAU(Month Active User):月活跃用户数量,指网站、app等去重后的月活跃用户数量

6、什么是接口幂等性问题,如何解决?

幂等:幂等(idempotent、idempotence)是一个数学与计算机学概念
一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同,比如付款时多次点击付款,实际上只会成功一次
接口幂等性:无论调用多少次,产生的效果是一样的
    -get 获取数据天然幂等
    -put 修改数据天然幂等
    -修改库存(数字加减):不幂等
    -delete 删除 天然幂等
    -post 新增数据,会出现不幂等的情况,要把它做成幂等性的

token机制
	1、下单接口的前一个接口,只要一访问,后端生成一个随机字符串,存到redis中,把随机字符串返回给前端
    2、然后调用业务接口请求时,把随机住非常携带过去,一般放在请求头部。
    3、服务器判断随机住非常是否存在redis中,存在表示第一次请求,然后redis删除随机字符串,继续执行业务。
    4、如果判断随机字符串不存在redis中,就表示是重复操作,直接返回重复标记给client,这样就保证了业务代码,不被重复执行
乐观锁机制--->更新的场景中
    update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1
	乐观锁主要使用于处理读多写少的问题
唯一主键
	利用数据库主键唯一约束的特性,解决了insert场景时幂等问题,但是主键要求不能自增
防重表
	建立一个去重表,利用唯一索引,注意的是,去重表和业务表应该在同一库中。如果重复就会请求失败,数据回滚
唯一ID
	调用接口时,生成一个唯一id,redis将数据保存到集合中(去重),存在即处理过。

7、什么是gil锁,有什么作用

# 1 GIL:Global Interpreter Lock又称全局解释器锁。本质就是一个互斥锁,
    # 2 保证了cpython进程中得每个线程必须获得这把锁才能执行,不获得不能执行
    # 3 使得在同一进程内任何时刻仅有一个线程在执行
    # 4 gil锁只针对于cpython解释器

# 为什么要有gil锁?
'''
    -python是动态强类型语言,因为有垃圾回收机制,如果同一个进程下有多个线程同时在执行,垃圾回收是垃圾回收线程【同一个进程下变量是共享的】,该线程做垃圾回收时,如果其他线程在运行,就可能会出并发安全的问题【数据安全的问题】,由于当时,只有单核cup【即便开启多线程,同一时刻,也只有一个线程在运行】,作者就强行做了一个GIL锁,保证在一个进程内,同一时刻只有一个线程执行,目的是为了防止垃圾回收线程做垃圾回收时,出现数据紊乱问题,所以加了gil锁
	-垃圾回收是垃圾回收线程,它在执行的时候,其他线程是不能执行的,而限于当时的条件,只有单核cpu,所以作者直接做了个GIL锁,保证一个进程内同一时刻只有一个线程在执行
'''

又被称为全局解释器锁,每个线程在执行的过程中都需要先获取GIL,作用就是限制多线程同时执行,使得在同一进程内任何时刻仅有一个线程在执行。
由于gil的存在,Python上开多线程时,每个线程都要竞争到gil后才运行,因此在Python中的多线程其实是假的
本质上是个互斥锁,互斥锁是为保护线程对共享资源的操作代码可以完整执行,不被其他线程介入。共享资源操作的代码段被称之为临界区,互斥锁的工作原理就是对临界区加锁

8、python的垃圾回收机制是什么样的

"""
-什么是垃圾回收?
    	-编程语言在运行过程中会定义变量--->申请了内存空间---》后期变量不用了---》这个内存空间应该释放掉
        -有些编程语言,这个操作,需要程序员自己做(c)
        -像java,python,go这些语言,都自带垃圾回收机制,可以自动回收内存空间,gc机制
"""
python中垃圾回收机制是默认自动回收的
python中的垃圾回收机制分为:引用计数,标记清除,分代回收
引用计数:
	在python中,一切皆对象,每个对象都会统计这个对象被引用的次数,每次被引用就会加一如a=10,先在内存创建一个数字对象10,然后将其赋值给变量a,这就是对10的一次引用,在有一个b=a,就是10的两次引用,执行del b时就会将引用计数减一,当计数减到0时,这个对象就会被判定为垃圾,系统会自动回收。但是引用计数,有个bug,如果两个变量循环引用,那么这些对象的引用计数永远不会变成0,这时候就需要另一个回收机制了
标记清除:
	首先确定根对象,并将其标记这些对象都不会被删除,然后检查有效对象所引用的对象,其也为有效对象就也将其标记,最后没有标记的都会被删除
分代回收:
	垃圾回收机制会更加频繁的处理新对象,会将新创建的对象分为一代,一代一般都存活的比较短,如果其在一代中存活了一段时间会被提升为二代,在二代中存活了一段时间又会被提升到三代,以此类推
    """
    	-算法原理是Python把对象的生命周期分为三代,分别是第0代、第1代、第2代。每一代使用双向链表来标记这些对象。每一代链表都有总数阈值,当达到阈值的时候就会出发GC回收,将需要清除的清除掉,不需要清除的移到下一代。以此类推,第2代中的对象存活周期最长的对象
    """
Python的垃圾回收机制主要运用在这三种算法之间,引用计数算法提高了回收垃圾对象的效率,标记清除算法保证了循环引用的完美处理,分代回收算法是为了增加垃圾回收的效率

9、解释为什么计算密集型用多进程,io密集型用多线程

CPU的工作机制:
    	# 当遇到i/o阻塞的时候,会自动剥夺CPU的执行权限
        # 当CPU遇到占用时间过长的时候也会自动剥夺CPU的执行权限
        # CPU的工作其实是来回切换的
i/o密集型:
    	# 有阻塞但是不会一直占用系统资源,中间会有等待如sleep
计算密集型:
    	# 与上一个相反,无阻塞但是会占用大量系统资源
    
"""
-由于python有gil锁,开启多条线程,统一时刻,只能有一条线程在执行
    -如果是计算密集型,开了多线程,同一时刻,只有一个线程在执行
    -多核cpu,就会浪费多核优势
    -如果是计算密集型,我们希望,多个核(cpu),都干活,同一个进程下绕不过gil锁
    -所以我们开启多进程,gil锁只能锁住某个进程中得线程,开启多个进程,就能利用多核优势
    
    
    -io密集型---》只要遇到io,就会释放cpu执行权限
    -进程内开了多个io线程,线程多半都在等待,开启多进程是不能提高效率的,反而开启进程很耗费资源,所以使用多线程即可
"""

10、为什么有了gil锁还要互斥锁

"""
	# 1 GIL 本身就是大的互斥锁
    # 2 同一个进程下,资源是共享的----》多条线程可以操作同一个变量
    # 3 多个线程操作同一个变量,就会出现数据安全问题
   	# 4 临界区:指一段代码或一段程序片段,需要在同一时间只能被一个线程执行---》多个线程操作临界区,会出现并发安全问题
   	gil锁释放不是我们控制的,比如在执行临界区中间,释放了,就会数据错乱问题
   	-1 线程遇到io
    -2 时间片轮转,时间片到了,就会自动切换
    gil锁并不锁住临界区,临界区需要我们自己用互斥锁加锁
"""
gil:全局解释器锁,线程要执行,必须先获得到gil锁,才能执行,本质就是互斥锁
互斥锁:为了保证多线程并发操作数据(变量)而设置的锁,保证在加锁和释放锁之间,其他线程不能操作
由于gil锁的机制是在多线程时,进行的一个竞争机制,所以可能会出现,一个全局变量,多个线程一起竞争,如global num=0,两个函数一起对其进行增加值,可能会出现在函数a中给num+1了,还未赋值到num中,函数b就已经拿到了num也给其+1了,但是由于a中的值还未赋值成功,所以b拿到的也是0,最后的结果一定不会是3
所以我们需要用到互斥锁,由于python,默认是没有上锁的,所以定义num后给其上个锁,这时就可以解决上述问题,得到正确的值

11、进程,线程和协程

概念:
	# 进程:是资源分配的最小单位,一个应用程序运行起来,至少有一个进程,进程管理器中就可以看到一个个的进程
	# 线程:是cpu调度,执行的最小单位,一个进程下至少有一个线程
	# 协程:单线程下的并发,程序层面控制的任务切换
代码如何实现:
    进程:
		-1 写一个类,继承Process,重写类的run方法---》实例化得到对象,对象.start 开启了进程
		-2 通过Process类实例化得到一个对象,传入任务 ,调用对象.start 开启了进程
    线程:
    	-1 写一个类,继承Thread,重写类的run方法---》实例化得到对象,对象.start 开启了进程
		-2 通过Thread类实例化得到一个对象,传入任务 ,调用对象.start 开启了进程
	协程:
    	-早期之前:借助于第三方gevent,基于greelet写的
        -async 和 await 关键字,不借助于第三方,开启协程  asyncio 包
        -必须写在一个函数前,async def task()---->这个函数执行的结果是协程函数
        -await 只要是io操作的代码,前面必须加 awai
你在哪里用过
	-我一般遇到计算密集型的操作,我会开多进程,io密集型的操作,我一般开多线程
	-闲来无事,爬别人数据,喜欢开多线程,爬虫io居多
    -程序中,异步做一件事情,也可以开多线程
    	比如一个视图函数,异步的吧数据写的文件中
        异步的发送钉钉通知
        异步的发送邮件
    -但实际上,在项目中,不需要我们开启进程线程
可以借助于第三方的框架比如celery就可以做异步的操作
    而celery的worker,就是进程线程架构
    -django框架,是支持并发,我们没有开启多进程和多线程,但是符合uwsgi的web服务器在进入djagno框架之前,开启了进程和线程来执行视图函数
"""
	不同进程下,资源是隔离的
    进程间通信:IPC 机制
    	-消息队列
"""

12、什么是鸭子类型

鸭子类型是python面向对象中描述接口的一个概念,区分与其他编程语言,
	比如java:实现接口,必须显示的继承一个接口
	而python:实现接口,遵循鸭子类型,不需要显示的继承一个接口(类),只要类中有对应的属性跟方法,我们就称这几个类的对象为同一种类型

13、什么是猴子补丁,有什么用途

1、猴子补丁:在程序运行过程中,动态替换的一种技术
2、比如咱们json模块、用内置的json,效率低,有一个第三方的ujson模块,在不改变原来程序代码,把程序中所有json都替换成ujosn,在程序运行的入口处:import ujson as json
3、 django中 pymysql的替换
    import pymsql
    pymysql.install_as_mysqlDB()
    
    
    
4、 gevent---》猴子补丁---》monkey.pach_all()---》动态的替换内部的会阻塞的代码
-time
-socket
-把所有内置的会释放gil锁的模块,动态替换成gevent自己写的,不会释放gil锁的模块
-同步代码:io操作,会阻塞,会释放gil锁,这条线程就会被释放cpu的执行
-动态的把所有同步的代码,都替换成异步代码,把所有会阻塞的代码,都替换
-异步代码,遇到io,不释放gil锁

14、什么是反射,python中如何使用反射

反射:是程序在运行过程中通过字符串来操作对象的属性和方法
1、反射类中的变量 : 静态属性,类方法,静态方法
2、反射对象中的变量、对象属性、普通方法
3、 反射模块中的变量
4、反射本文件中的变量
-getattr
-setattr
-hasattr
-delattr

15、http和https的区别

-https=http+ssl/tls
-监听端口不一样,80,443、
-保证了http传输的安全
"""
# 名字
# HTTP协议,英文全称是Hyper Text Transfer Protocol,是超文本传输协议
# HTTPS协议,英文全称Hyper Text Transfer Protocol over SecureSocket Layer,超文本传输安全协议
# 默认端口
# HTTPS 和 HTTP 的默认端口不同(443和80)
# 核心区别
# HTTPS在 HTTP与 TCP 之间加入了一个加密/身份验证层,提供了身份验证与加密通讯
HTTP+ SSL / TLS,也就是在 http上又加了一层处理加密信息的模块,比 http安全,可防止数据在传输过程中被窃取、改变,确保数据的完整性
https=http+ssl


# HTTP 由于是明文传输,主要存在三大风险:窃听风险、篡改风险、冒充风险
"""

16、从浏览器输入一个地址,到看到页面信息,经历的过程

1. 输入地址
2. 浏览器查看本地缓存有直接显示到第三步
3. 发http请求前进行一个路由解析,获取对应的ip地址
4. 浏览器像服务器发起tcp请求,三次握手
5. 握手成功后,发送http请求,请求数据包
6. 服务器收到请求后,将数据返回给浏览器
7. 浏览器收到响应
8. 读取页面内容进行渲染解析html源码
9. 生成DOM树解析css样式js脚本
10. 客服端与服务器交互
11. ajax查询

"""
1 从浏览器输入一个地址,到看到页面信息,经历的过程
	1 在浏览器中输入的是:【地址,不带端口,默认是80端口】域名---》要做域名解析(DNS解析)---》把域名解析成ip地址+端口的形式---dns解析---》(浏览器缓存(一旦之前访问过这个地址,浏览器会自动加缓存,再访问--》直接从缓存中获取--》F5强制刷新或者浏览器有无痕)--》dns解析:先解析本地host文件,上一级递归解析服务 ,13台根dns)--》如果解析不到---》页面就会报错
    2 解析完后,向解析出的域名和端口,准备建立TCP连接,可靠链接,tcp处于传输层,进行3次握手,链接简历	
    3 像解析出的地址发送http的get请求---》http协议又有很多东西,暂时先不说
    4 如果后端服务是使用nginx转发,做反向代理服务器,nginx把http请求转发给web框架(django,flask)--》django请求生命周期---》分离项目和混合项目
    5 后端服务器以http响应的形式返回给客户端浏览器
    6 客户端浏览器把http响应体的内容展示在浏览器上,但是http响应还有:状态码,响应头。。
    7 四次挥手断开tcp连接---》这个链接不一定会断开---》http协议版本
"""

17、左连接,右连接,内连接,全连接:MySQL不能直接支持

内连接,就是inner join
select * from course c inner join teacher t on c.t_id = t.t_id 
select * from course c ,  teacher t where c.t_id = t.t_id  # 逗号的连表方式就是内连接
内连接就是两张表,根据某个字段进行连接,都有值的情况下显示
外连接分为左连接和右连接
左连接
select * from course c left join teacher t  on  c.t_id = t.t_id
两张表,根据某个字段进行连接,以左表为基准,右表中没值的就显示NULL
右连接
select * from course c right join teacher t on   c.t_id = t.t_id 
两张表,根据某个字段进行连接,以右表为基准,左表中没值的就显示NULL
MySQL中其实并没有全链接,不过可以用union将左连接和右连接的结果合并再去重
select * from a left join b on a.id = b.id
union
select * from a right join b on a.id = b.id
会将两张表所有值都显示,没值的就会显示NULL

"""
# 笛卡尔积
	select * from book,publish where book.publish_id=publish.id;
        第一个表
    id  name  age   publish_id
    1   xx    11      1
    2    yy    12     1
    
    第二个表
    id  name  age
    1   xx    11
    2    yy    12
    
    1   xx    11      1  1   xx    11
     1   xx    11    2    yy    12
    2    yy    12     1  1   xx    11
    2    yy    12     1
"""

18、union和union all的区别?

union在对两个结果会进行去重,按照默认顺序给显示出来
union all不会去重,而是将所有数据都显示出来
1会排序
2不会排序
用一条查询语句
select * from student2 where id < 4
union
select * from student2 where id > 2 and id < 6
用1时会出现一条id=3的结果,用2会出现两条
所以说,2只会合并结果,并不会去重排序,在不要求去重的情况下,用2比1效率高

19、一句sql查询慢,如何排查优化

索引优化:添加一下索引
SQL重构:重构SQL语句用join代替子查询用union代替or查询
查询限制:限制返回结果的行数
缓存查询结果:采用redis等缓存工具将结果缓存下来
数据库服务器优化:调整连接池
数据库结构优化:分表,分区等操作
查询语句优化:避免select *的操作,尽量只查需要的字段


"""
# 1 orm  原生sql
# 2 接口响应速度慢---》定位到是sql问题
	-索引优化:分析sql有没有走索引----》EXPLAIN SELECT * FROM orders WHERE name = 123;
	在表中添加合适的索引可以显著提升查询效率。可以通过 EXPLAIN 命令来查看查询计划,判断是否使用了索引,如果没有使用索引,就需要考虑添加索引
    -避免全表扫描:避免在大表上进行全表扫描,可以通过限制查询条件或者使用分页查询来解决
        -使用分页,避免全表搜索,扫码
    -优化查询语句:
        EXPLAIN SELECT * FROM orders WHERE name like 123%;
    	-优化sql,不要写 前面的模糊查询
        -尽量使用主键查询,尽量不模糊匹配
    -数据库表结构优化 
    	-大表拆成小表
        
    -做数据库读写分离
    -分库分表
"""

20、tcp 三次握手和四次挥手

"""
tcp协议---》处于osi7层协议的传输层,可靠连接,使用三次握手,四次挥手保证了可靠连接,数据不会丢失
-SYN:SYN=1 表示要建立连接
-ACK:ACK=1 表示我收到了,允许
-seq:随机数,建立连接无论客户端还是服务端要建立连接就要要携带
-ack:回应请求就要加1返回
-FIN:表示断开连接
三次握手:
    第一次:客户端向服务端发送建立连接请求,【携带一个随机数】(SYN=1,seq=随机数)
    第二次:服务端回应客户端的建立连接请求(ACK=1,ack=随机数+1),服务端发送建立连接请求(SYN=1,seq=另一个随机数)
    第三次:客户端回应服务端的建立连接请求(ACK=1,ack=另一个随机数+1)
四次挥手:
	第一次:客户端向服务端发起断开连接的请求(FIN=1,seq=随机数)
    第二次:服务端收到后,回复这个请求(ACK=1,ack=随机数+1)
    
   	第三次:服务端向客户端发起断开连接的请求(FIN=1,seq=另一个随机数,ACK=1,ack=随机数+1)
    第四次:客户端收到后,回复这个请求(ACK=1,ack=另一个随机数+1)
# 洪水攻击 ddos:
    同一时间有大量的客户端请求建立连接 会导致服务端一直处于SYN_RCVD状态,服务端接收到了大量的syn请求,处于rcvd状态
"""
三次握手:
	TCP协议,需要在客户端和服务端之间交换三个TCP报文段,称之为三次握手,采用三次握手主要是为了防止已失效的连接请求,突然又传送到了,因而发生错误
	首先,客户端A主动打开,服务器B被动打开,由客户端向服务器发出连接请求的报文段
    然后,B收到A连接请求报文段后,如果同意,则向A发回确认
    最后,A收到此报文段后,向B给出确认
    此时,TCP的连接已经建立成功了
四次挥手:
	TCP的连接释放过程比较复杂,双方都可以释放连接
    比如客户端A的应用进程先向其TCP发出连接释放请求,并停止发送数据,主动关闭TCP连接,等待服务端B的确认
    在B收到确认后发出确认号,从A到B的这个方向连接就断了,此时TCP协议处于一个半连接半关闭状态,B若要发送数据,A仍要接收
    若B没有要发送的数据了,其应用进程就通知TCP协议释放连接
    A收到连接释放报文段时,必须发出确认

21、osi七层协议,哪七层,每层有哪些

"""
si七层:                    应用层 表示层 会话层    传输层  网络层  数据链路层  物理连接层
# 五层结构(TCP/IP五层协议):  应用层(三个合成一个)    传输层  网络层  数据链路层  物理连接层

# 应用层 表示层 会话层(应用层)
	-应用层协议:HTTP,FTP,DNS,    SNMP,SMTP,Telnet
# 表示层:https=http+ssl  的加密
# 会话层:负责建立、管理和终止表示层实体之间的会话连接


# 传输层(运输层):
    -tcp协议:三次握手四次挥手可靠链接
    -udp协议:不可靠传输
	-端口:端口协议
# 网络层
	-ip地址协议:ip,点分十进制表示
    -icmp协议:ICMP(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议簇的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用
    
# 数据链路层:
	-PPP:点对点协议(Point to Point Protocol,PPP)为在点对点连接上传输多协议数据包提供了一个标准方法
    -ARP:地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议
	-mac地址:以太网协议
	-数据帧:电信号的分组方式
# 物理层:
	-ISO2110,IEEE802,IEEE802.2
    -物理介质
    -网线
"""

物理层:
	传输单元是比特,功能是将二进制比特流从一台机器传输到另一台相邻机器
数据链路层:
	由于物理层传输的传输的比特流不能保证没有错误,而且也不能确定接受到的位可能多于,等于或者少于发送的位,而且可能有不同的值。所以就需要数据链路层,将比特流进行划分成帧,主要就是检测和纠正物理层中可能出现的错误
    传输单元是帧,功能是以一定的可靠性将链路层帧从一台机器传输到另一台相邻的机器
    采用的是以太网协议
网络层:
	传输单元是分组,功能是广域网环境的端到端数据传输,将数据从源机器送到目的机器可能沿途经过许多的跳(hop)
    采用的是IP协议
传输层:
	位于应用层和网络层之间,基于网络层提供的服务,向分布式应用程序提供通信服务
    传输单元是报文段,传输层起到了一个承上启下的作用,他是面向通信部分的最高层,同时也是用户功能的最底层
    采用的主要是TCP或者UDP协议
会话层:
	负责维护两个会话主机之间连接的建立、管理和终止以及数据的交换
表示层:
	不同计算机可能使用不同的数据表示方法
    负责通信系统之间的数据格式变换、数据加密与解密、数据压缩与恢复
应用层:
	通过分布在不同的计算机内的多个进程的交互完成特定网络应用
    应用层协议定义了应用进程间的通信和交互的规则,不同的网络应用需要不同的应用层协议
    他的传输单元是消息

22、tcp和udp的区别?

"""
-tcp是面向连接的可靠协议
-udp无连接的不可靠协议

-都是处于传输层

-比如:
	udp:一些聊天,dns协议用的udp协议
	tcp:http  mysql,redis客户端服务端通信
"""

UDP提供无连接服务:
	在传送数据之前不需要建立任何连接,对方在收到UDP报文后,不需要给出任何确认,虽然UDP不提供可靠交付,但在某种情况下UDP是一种最有效的工作方式
    支持单播,多播和广播
    比较简单,处理起来速度比较快,适用于很多应用如多媒体应用等
TCP提供面向连接服务:
	连接建立、数据传输、连接释放
    由于TCP提供可靠的,面向连接的运输服务,因此不可避免地增加了许多的开销。这不仅使协议数据单元的首部增大很多,还要占用许多的处理机资源
    只支持单播,不支持多播和广播
    比较复杂,处理起来速度较慢也更耗费资源,用于大多数应用,如万维网,电子邮件等

23、wsgi uwsgi uWSGI,cgi,fastcgi 分别是什么?

cgi:
    通用网关接口,是外部应用程序与Web服务器之间的接口标准,用来规定一个程序该如何与web服务器程序之间通信,从而可以让这个程序跑在web服务器上
fastcgi:
    fastcgi是Web服务器(ex:nginx)和语言解释器(ex:uWsgi)两者底层的通信协议的规范,是对CGI的开放的扩展。
wsgi:
    它是用在 python web 框架编写的应用程序与后端服务器之间的规范(如django和wWSGI之间),让你写的应用程序可以与后端服务器顺利通信。
uWSGI:
    它是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。用于接收前端服务器转发的动态请求并处理后发给 web 应用程序。
uwsgi:
    它是uWSGI服务器实现的独有的协议,用于定义传输信息的类型,是用于前端服务器与 uwsgi 的通信规范。
一个Django应用,通过WSGI协议连接uWSGI服务器,uWSGI服务器实现WSGI、http等协议,通过uwsgi协议和Nginx服务器实现http的动态请求和转发以及结果回复。

"""
# CGI:通用网关接口(Common Gateway Interface/CGI),CGI描述了服务器(nginx,apache)和请求处理程序(django,flask,springboot  web框架)之间传输数据的一种标准
    	# 所有bs架构软件都是遵循CGI协议的
    	# 一句话总结: 一个标准,定义了客户端服务器之间如何传数据
        
# FastCGI:快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本
	# FastCGI致力于减少网页服务器与CGI程序之间互动的开销,从而使服务器可以同时处理更多的网页请求
    # 常见的fastcgi服务器:Apache,Nginx,Microsoft IIS
    # CGI的升级版
    
# WSGI:Python Web Server Gateway Interface,缩写为WSGI,Python定义的Web服务器和Web应用程序或框架之间的一种通用的接口
	#一句话总结: 为Python定义的web服务器和web框架之间的接口标准
    
    
#uWSGI:符合wsgi协议的web服务器,用c写的,性能比较高,咱们通常用来部署django,flask
	#一句话总结:一个Web Server(web服务器),即一个实现了WSGI协议的服务器,处理发来的请求及返回响应。

    # xml:socket 标签

# uwsgi:uWSGI服务器实现的独有的协议,用于定义传输信息的类型,是用于前端服务器与 uwsgi 的通信规范
	# 1、一句话总结: uWSGI自有的一个协议
        uWSGI:web服务器,等同于wsgiref
        uwsgi:uWSGI自有的协议
	

# 符合WSGI协议的web服务器
    wsgiref,werkzeug(一个是符合wsgi协议的web服务器+工具包(封装了一些东西))
    uWSGI 用c语言写的,性能比较高
    gunicorn:python写的
    
  
web服务器到底是什么?服务器中间件
客户端(浏览器,app)  跟   服务端(web框架)之间的东西,服务器中间件
# nginx  apache  是一类东西,就是做请求转发,符合fastcgi服务器
# uWSGI,gunicorn 只针对于python的web框架
# tomcat,jboss,weblogic 只针对java的web框架
# php-fpm  针对于php的框架
"""

24、如何自定制上下文管理器

上下文管理器(Context Manager)是Python中的一种编程模式,用于管理资源的获取和释放。
在python当中,我们知道with的用法,是一种上下文管理机制。比如with open(file,'w') as f:  这种方法下,就集成了open和close.我们也可以自定义一个上下文管理器。
1. 必须要有__enter__和__exit__两个魔术方法。

2. 使用 contextlib.contextmanager 装饰器,可以将一个函数变为一个上下文管理器,不过要求这个被修饰的函数必须为一个生成器。所以,函数中要有yield的存在。

"""
# python的一种编程模式,用于进入和退出之后自动执行一些代码的场景

# 一个对象如果实现了__enter__和___exit__方法,那么这个对象就支持上下文管理协议,即with语句
# 上下文管理协议适用于那些进入和退出之后自动执行一些代码的场景,比如文件、网络连接、数据库连接或使用锁,使用事务的编码场景等
# session--->创建session对象--->最后用完要调用commit,close
"""

25、Python是值传递还是引用传递

函数参数传递机制的问题在本质上都是调用函数和被调用函数过程在调用时进行通信的方法问题基本的传递有两种值传递和引用传递
值传递就是在值传递过程中,被调函数的形参都是作为局部变量处理,在堆栈中开辟了内存空间存放主调函数放进来的实参的值从而成为了实参的一个副本,值传递的特点就是被调函数对形参的任何操作都是不会影响主调函数的实参变量的值
引用传递就是在值传递过程中,被调函数的形参虽然也作为局部变量处理,在堆栈中开辟了内存空间,但是存放主调函数放进来的实参的地址,所以对形参的任何操作都变成了简介寻址,正因如此被调函数对形参做的任何操作都会影响主调函数中实参变量

由于python中有可变类型和不可变类型,所以python不允许程序员选择采用值传递还是引用传递。而是由程序运行时,传进来的是不可变类型那么就是值传递,如果传进来的是可变类型,就是引用传递


"""
# 严格意义上来说,python既不是值传递,也不是引用传递,python是自己的传递方式,规则是:
    如果传递的是不可变类型,在函数中修改,就不会影响原来的变量
    如果传递的是可变数据类型,在函数中修改,不会影响原来的变量,修改,而不是重新赋值

# python一切皆对象---》(你不要说)内部函数是一切皆引用(对象本质就是地址,就是引用)



# 什么是值,什么是引用
	-值就是一个变量=具体的值(一块内存空间放着这个变量的值)
    -引用是一个变量=内存地址(内存地址指向了值)
    -所有python才有了可变和不可变类型
# 什么是值传递 什么是引用传递
	-如果是值传递,函数中修改了传递的值,不会影响原来的
    -如果是引用传递,函数中修改了传递的引用,就会影响原来的
"""

26、什么是迭代器,生成器,装饰器

既有__iter__方法, 也含有__next__方法的称为迭代器对象
文件对象即是可迭代对象又是迭代器对象
可迭代对象调用__iter__方法
可以给我们提供一种不依赖索引取值的方法

range()就是一个典型的生成器,生成器的作用就是节省空间
生成器一定是迭代器,迭代器不一定是生成器
生成器中一定有个yield

在不改变被装饰对象内部代码和原有调用方式的基础之上添加额外的功能

27、django的信号用过吗?如何用,干过什么

# 内置信号:
	#Model signals
    pre_init                    # django的modal执行其构造方法前,自动触发
    post_init                   # django的modal执行其构造方法后,自动触发
    pre_save                    # django的modal对象保存前,自动触发
    post_save                   # django的modal对象保存后,自动触发
    pre_delete                  # django的modal对象删除前,自动触发
    post_delete                 # django的modal对象删除后,自动触发
    m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
Request/response signals
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发
    got_request_exception       # 请求异常后,自动触发
Test signals
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
Database Wrappers
    connection_created          # 创建数据库连接时,自动触发

1. 首先写个函数,需要放到__init__中,因为这个代码需要先执行
2. 绑定内置信号
3. 等待触发
也可以使用receiver装饰器将内置信号传入
也可以自定义信号
1. 定义信号
使用res = django.dispatch.Signal()
2. 绑定信号
用res.connect(执行的函数)
3. 触发信号res.send,可以用toppings,size 传参

我用信号做过用户注销后的短信通知
就是用post_save,在model对象保存后,吊起信号,发送一条短信的通知

28、什么是深拷贝,什么是浅拷贝,如何使用

浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。
	1. 可使用数据本身的构造器,本身就是为新变量重新分配一块内存,和原来变量的内存不一样,但是值一样,所以用is比较会出False
    2. 对于可变类型可以使用切片,不可用于字典和集合
    3. copy.copy() 函数
    4. 对字符串和元组使用上述方法,都只是开辟了内存存储原对象的引用,而不是存储原对象的子对象的引用。
    5. 和赋值不同,赋值只是把原对象的引用给到新对象

深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联
	1. 采用copy.deepcopy()来实现对象的深拷贝

1、用过什么框架

2、什么情况下用Django,什么情况下用Flask

3、设计模式

4、装饰器

5、多线程多进程

6、加密方法

7、消息队列

8、卡夫卡

9、Redis可以做什么

10、python第三方库用过哪些

11、数据处理的第三方库:正则

12、写没写过技术文档

13、数据库主要用那些

14、MySQL建表要求

15、MySQL慢查询优化

16、SQL执行计划

17、个人技术提升,从哪方面提升

18、读过源码吗?

19、DJango源码里,你映像比较深的

20、公司内部代码书写规范要求

posted @ 2023-09-05 09:58  岳宗柯  阅读(53)  评论(0编辑  收藏  举报