前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python技术面试题(八)

python技术面试题(八)

作者头像
小闫同学啊
发布2019-07-18 14:46:45
5990
发布2019-07-18 14:46:45
举报
文章被收录于专栏:小闫笔记小闫笔记

正文共: 3814 字6 图 预计阅读时间: 10 分钟

笔试题

1.python中is和==的区别?

答:is是同一性运算符,是判断两个对象的id地址是否相同,是否指向同一块区域;==是比较操作符,用来判断两个对象的数据类型和值是否相同。

2.Django里QuerySet的get和filter方法的区别?

答:filter返回的是一个对象列表,如果查不到,返回一个空列表。get得到的是一个具体的对象,如果查不到,会报错。

3.列出至少4种HTTP请求返回状态码,并解释其意思。

状态码

解释说明

302

跳转,新的url在响应的location头中给出

303

浏览器对于POST的响应进行重定向

307

浏览器对于GET的响应重定向至新的url

503

服务器维护或者负载过重未应答

只列出一些特殊的,常见的大家都知道了,此处不做列出。

4.多线程和多进程的区别?

进程是资源分配的单位,线程是操作系统调度的单位。进程切换需要的资源最大,效率低;线程切换需要的资源一般,效率一般(不考虑GIL的情况)。多进程和多线程根据CPU核数不一样可能是并行的。线程是基于进程存在的。

5.Flask中请求钩子的理解和应用?

在客户端和服务器交互的过程中,有些准备工作扫尾工作需要处理的时候,为了让每个视图函数避免编写重复的代码,Flask提供了通用设施的功能,这就是请求钩子

我们的项目中,在完善CSRFToken逻辑和拦截普通用户进入管理员页面的时候,用到了请求钩子。

请求钩子是通过装饰器的形式实现的,有4种

1.before_first_request:在处理第一个请求前执行

2.before_request:在每次请求前执行,在该装饰函数中,一旦return,视图函数不再执行

a.接受一个参数:视图函数作出的响应

b.在此函数中可以对响应值,在返回之前做最后一步处理,再返回

3.after_request:如果没有抛出错误,在每次请求后执行

4.teardown_request:在每次请求后执行

a.接受一个参数:用来接收错误信息

但是我们常用的只有2和3两种,在项目中具体的代码展示一下,方便大家进行回忆:

代码语言:javascript
复制
1 #使用请求钩子拦截所有的请求,通过的在cookie中设置csrf_token
 2    @app.after_request
 3    def after_request(resp):
 4        #调用系统方法,获取csrf_token
 5        csrf_token = generate_csrf()
 6
 7        #将csrf_token设置到cookie中
 8        resp.set_cookie("csrf_token",csrf_token)
 9
10        #返回响应
11        return resp
代码语言:javascript
复制
1# 使用请求钩子,拦截用户的请求,只有访问了admin_blue,所装饰的视图函数需要拦截
2# 1.拦截的是访问了非登录页面
3# 2.拦截的是普通的用户
4@admin_blue.before_request
5def before_request():
6    if not request.url.endswith("/admin/login"):
7        if not session.get("is_admin"):
8            return redirect("/")

intern机制

Python3的解释器中实现了小数字和字符串缓存的机制,小数字的缓存范围是[-5 ~ 256],字符串的缓存位数默认是20位。

字符串缓存机制实验:

代码语言:javascript
复制
>>> a = 'xx' * 20
>>> b = 'xx' * 20
>>> a is b
False
>>> a = 'x' * 3
>>> b = 'x' * 3
>>> a is b
True

可以看出字符串长度没有超过20,两个id是一致的,因为小于20,提前缓存好了,我们赋值操作其实是一个引用,两个都指向同一块内存空间。如果长度超过20,没有缓存,会新开辟内存,所以他们的id地址不一样。

小数字的缓存机制实验:

代码语言:javascript
复制
>>> a = -6
>>> b = -6
>>> a is b
False
>>> a = -5
>>> b = -5
>>> a is b
True

可以看出如果是-5的话,两个变量的id是一样的,因为提前缓存好了,他们只是一个引用,指向同一块空间地址。如果是-6的话就相当于重新开辟内存空间。

还有一种情况,就是如果两个字符串中含有除数字、字母下划线的任意一个符号,那么会触发intern机制,他们的内存地址也是不一样的。不论你的字符串多短。

gc模块

一.垃圾回收机制

Python中的垃圾回收是以引用计数为主,分代收集为辅。

1、导致引用计数+1的情况
  • 对象被创建,例如a=23
  • 对象被引用,例如b=a
  • 对象被作为参数,传入到一个函数中,例如func(a)
  • 对象作为一个元素,存储在容器中,例如list1=[a,a]
2、导致引用计数-1的情况
  • 对象的别名被显式销毁,例如del a
  • 对象的别名被赋予新的对象,例如a=24
  • 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
  • 对象所在的容器被销毁,或从容器中删除对象
3、查看一个对象的引用计数
代码语言:javascript
复制
import sys
a = "hello world"
sys.getrefcount(a)

可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1

二.循环引用导致内存泄露

内存泄漏

代码语言:javascript
复制
申请了某些内存,但是忘记了释放,那么这就造成了内存的浪费,久而久之内存就不够用了
1. 让程序产生内存泄漏
代码语言:javascript
复制
import gc

class ClassA():
    def __init__(self):
        print('object born,id:%s'%str(id(self)))

def f2():
    while True:
        c1 = ClassA()
        c2 = ClassA()
        c1.t = c2
        c2.t = c1
        del c1
        del c2

#python默认是开启垃圾回收的,可以通过下面代码来将其关闭
gc.disable()
f2()

执行f2(),进程占用的内存会不断增大。

  • 创建了c1,c2后这两块内存的引用计数都是1,执行 c1.t=c2c2.t=c1后,这两块内存的引用计数变成2.
  • 在del c1后,引用计数变为1,由于不是为0,所以c1对象不会被销毁;同理,c2对象的引用数也是1。
  • python默认是开启垃圾回收功能的,但是由于以上程序已经将其关闭,因此导致垃圾回收器都不会回收它们,所以就会导致内存泄露。

三.垃圾回收

代码语言:javascript
复制
class ClassA():
    def __init__(self):
        print('object born,id:%s'%str(id(self)))

def f2():
    while True:
        c1 = ClassA()
        c2 = ClassA()
        c1.t = c2
        c2.t = c1
        del c1
        del c2
        gc.collect()#手动调用垃圾回收功能,这样在自动垃圾回收被关闭的情况下,也会进行回收

#python默认是开启垃圾回收的,可以通过下面代码来将其关闭
gc.disable()

f2()
有三种情况会触发垃圾回收:
  1. 当gc模块的计数器达到阀值的时候,自动回收垃圾
  2. 调用gc.collect(),手动回收垃圾
  3. 程序退出的时候,python解释器来回收垃圾

四. gc模块的自动垃圾回收触发机制

在Python中,采用分代收集的方法。把对象分为三代,一开始,对象在创建的时候,放在一代中,如果在一次一代的垃圾检查中,该对象存活下来,就会被放到二代中,同理在一次二代的垃圾检查中,该对象存活下来,就会被放到三代中。

gc模块里面会有一个长度为3的列表的计数器,可以通过gc.get_count()获取。

例如(488,3,0),其中488是指距离上一次一代垃圾检查,Python分配内存的数目减去释放内存的数目,注意是内存分配,而不是引用计数的增加。例如:

代码语言:javascript
复制
print gc.get_count() # (590, 8, 0)
a = ClassA()
print gc.get_count() # (591, 8, 0)
del a
print gc.get_count() # (590, 8, 0)

3是指距离上一次二代垃圾检查,一代垃圾检查的次数,同理,0是指距离上一次三代垃圾检查,二代垃圾检查的次数。

gc模快有一个自动垃圾回收的 阀值,即通过gc.get_threshold函数获取到的长度为3的元组,例如(700,10,10) 每一次计数器的增加,gc模块就会检查增加后的计数是否达到阀值的数目,如果是,就会执行对应的代数的垃圾检查,然后重置计数器

例如,假设阀值是(700,10,10):

代码语言:javascript
复制
当计数器从(699,3,0)增加到(700,3,0),gc模块就会执行gc.collect(0),即检查一代对象的垃圾,并重置计数器为(0,4,0)
当计数器从(699,9,0)增加到(700,9,0),gc模块就会执行gc.collect(1),即检查一、二代对象的垃圾,并重置计数器为(0,0,1)
当计数器从(699,9,9)增加到(700,9,9),gc模块就会执行gc.collect(2),即检查一、二、三代对象的垃圾,并重置计数器为(0,0,0)

优质文章推荐:

公众号使用指南

redis操作命令总结

前端中那些让你头疼的英文单词

Flask框架重点知识总结回顾

项目重点知识点详解

难点理解&面试题问答

flask框架中的一些常见问题

团队开发注意事项

浅谈密码加密

Django框架中的英文单词

Django中数据库的相关操作

DRF框架中的英文单词

重点内容回顾-DRF

Django相关知识点回顾

美多商城项目导航帖

项目重要技术点介绍

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈技术精选 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 笔试题
    • 1.python中is和==的区别?
      • 2.Django里QuerySet的get和filter方法的区别?
        • 3.列出至少4种HTTP请求返回状态码,并解释其意思。
          • 4.多线程和多进程的区别?
            • 5.Flask中请求钩子的理解和应用?
            • intern机制
            • gc模块
              • 一.垃圾回收机制
                • 1、导致引用计数+1的情况
                • 2、导致引用计数-1的情况
                • 3、查看一个对象的引用计数
              • 二.循环引用导致内存泄露
                • 1. 让程序产生内存泄漏
              • 三.垃圾回收
                • 有三种情况会触发垃圾回收:
              • 四. gc模块的自动垃圾回收触发机制
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档