python中常见面试题

1.简述 with 方法打开处理文件帮我我们做了什么?

with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
with语句即“上下文管理器”,在程序中用来表示代码执行过程中所处的前后环境 上下文管理器:含有__enter__和__exit__方法的对象就是上下文管理器。
enter():在执行语句之前,首先执行该方法,通常返回一个实例对象,如果with语句有as目标,则将对象赋值给as目标。
exit():执行语句结束后,自动调用__exit__()方法,用户释放资源,若此方法返回布尔值True,程序会忽略异常。
使用环境:文件读写、线程锁的自动释放等

2.了解类型注解么?

首先,Python是一种动态语言,变量和函数的参数是不区分类型的。

Python解释器会在运行的时候动态判断变量和参数的类型,这样的好处是编写代码速度很快,很灵活,但是坏处也很明显,不好维护,可能代码写过一段时间重新看就很难理解了,因为那些变量、参数、函数返回值的类型,全都给忘记了。

在阅读别人的代码时,无法看出变量或参数的类型,这样对工作效率带来很大影响。

因此,在Python3中新添加了“类型注解”特性,可以给参数、函数返回值和变量的类型加上注解,该注解仅仅是注释而已,对代码运行不会产生任何影响,真正的变量类型还是由Python解释器决定,你所做的只是提高代码可读性,并不会像静态语言中变量类型定义后就无法修改(强转除外)。

#coding:utf-8


def list_to_str(param_list: list, connect_str: str=" ") -> str:
    """列表转字符串

    使用join方法将列表转为字符串并返回
    :param param_list: 列表
    :param connect_str: 需要插入的字符,默认为一个空格
    :return:转换成功的字符串
    """
    demo_tuple: tuple = (1, 2)
    demo_dict: dict = {"1": 1}
    return connect_str.join(param_list)


if __name__ == '__main__':
    result = list_to_str(["Hello", "world"])
    print(result)

以上代码可以看出,一般变量和函数参数注解格式为“参数:类型”,默认参数是在类型的后面加“=默认值”,函数的返回值注解格式为“-> 类型:”,函数的冒号在注解后方。
Python提供了一个工具方便我们测试类型注解的正确性

  • 类型注解仅仅起到了注释作用,那我们应该如何知道它的正确性呢?

pip install mypy
使用方法:

mypy demo.py
若无错误则无输出,反之会输出如下:

D:\code\web\flaskweb>mypy demo.py
demo.py:12: error: Incompatible return value type (got “str”, expected “int”)

3.例举你知道 Python 对象的命名规范
  • 变量命名:字母数字下划线,不能以数字开头

    • 单下划线开头变量
      单下划线开头的变量标明是一个受保护(protected)的变量,原则上不允许直接访问,但外部类还是可以访问到这个变量。
      这只是程序员之间的一个约定,用于警告说明这是一个私有变量,外部类不要去访问它。
    • 双下划线开头变量
      双下划线开头的,表示的是私有类型(private)的变量。 只能是允许这个类本身进行访问了, 连子类也不可以.
      以双下划线开头,并且以双下划线结尾的,是内置变量.
      内置变量是可以直接访问的,不是 private 变量,如__init____import__或是__file__
      ★不要自己定义内置变量
      xxx_,单下划线结尾的变量一般只是为了避免与 Python 关键字的命名冲突
      USER_CONSTANT,大写加下划线,对于不会发生改变的全局变量,使用大写加下划线
  • 函数和方法(类中叫做方法,模块中称作函数)命名:

总体而言应该使用小写和下划线,如:create_user():
私有方法 : 小写和一个前导下划线,如 def _create_user(self):
私有方法和私有变量一样,并不是真正的私有访问权限。
一般函数不要使用两个前导下划线(当遇到两个前导下划线时,Python 的名称改编特性将发挥作用)。
特殊方法 : 小写和两个前导下划线,两个后置下划线 def __init__(self):
这种风格只应用于特殊函数,比如操作符重载等。
函数参数 : 小写和下划线,缺省值等号两边无空格 def __init__(self, param=None):
不要滥用 *args 和 **kwargs,可能会破坏函数的健壮性
类命名:

  • 类总是使用驼峰格式命名,即所有单词首字母大写其余字母小写/
    如:Class CreateUser():
    类名应该简明,精确,并足以从中理解类所完成的工作。
    常见的一个方法是使用表示其类型或者特性的后缀,例如:SQLEngine ,MimeTypes
    对于基类而言,可以使用一个 Base 或者 Abstract 前缀
  • 包和模块:

小写字母、数字和下划线

4. 如何区别可变数据类型和不可变数据类型

可变数据类型:在内存id不变的情况下,数据的值可以改变

不可变数据类型:数据的值不能发生改变,如果值发生改变,那么内存id也会改变,这样就不是同一个数据了。

5.一个编码为 GBK 的字符串 S,要将其转成 UTF-8 编码的字符串,应如何操作?
#!/usr/bin/python3
import chardet

demo_str = "demo string".encode("gbk")
demo_str = demo_str.decode('gbk').encode('utf-8')
print(demo_str)
# chardet.detect()可以检测编码格式
print(chardet.detect(demo_str))
6. [[1,2],[3,4],[5,6]]一行代码展开该列表,得出[1,2,3,4,5,6]
#!/usr/bin/python3
question_list = [[1, 2], [3, 4], [5, 6]]
# 使用列表推导式嵌套的时候,注意前后的调用关系,前推导式的值需要在后面书写才能生效
# 需要输出的值放到推导式的最前面,生成输出值的推导式在最后面
print([list_int for inside_list in question_list for list_int in inside_list])
7.python中remove del和pop的区别
del  根据索引删除元素 还可以直接删除变量或者列表
		报错类型:IndexError: list assignment index out of range
		
pop 默认删除末尾的元素 并且会返回
		报错类型:IndexError: pop from empty list
		
remove 根据元素删除
		报错类型:ValueError: list.remove(x): x not in list
8. 下面的代码输出的结果是什么?

a = (1, 2, 3, [4, 5, 6, 7], 8)
a[3][0] = 2 # (1, 2, 3, [2, 5, 6, 7], 8)
列表是可变数据类型,数据的值可以修改的
这里只是修改了元祖子对象的值,而不是修改了元祖的值
修改可变类型的值不会改变内存id,因此元祖的引用还是没有发生变化
可以这么理解,只要不修改元祖中值的内存id,那么就可以进行“修改元组”操作

  • 扩展,面试官可能会问到:元祖是否可以被修改?
    答:元组是不可变数据类型,因此不能修改元祖中的值,但是如果元组中有可变数据类型,那么可以修改可变数据类型中的值,修改可变数据类型的值并不会使其内存id发生变化,所以元祖中元素中的内存id也没有改变,因此就做到了“修改元祖”操作。
9. read、readline 或者 readlines,简述它们各自的作用

read:读取整个文件。
readline:读取下一行,使用生成器方法。
readlines:读取整个文件到一个迭代器以供我们遍历

10.json 序列化时,默认遇到中文会转换成 unicode,如果想要保留中文怎么办?
#!/usr/bin/python3
import json

dict_demo = {"name": "旭东"}
# 使用dumps的默认参数ensure_ascii
print(json.dumps(dict_demo, ensure_ascii=False))
11.python 字典和 json 字符串相互转化方法
import json

dict_demo = {"a": 1, "b": 2}
# 序列化:使用json.dumps()将python类型转为json字符串
json_demo = json.dumps(dict_demo)
print(type(json_demo))
# 使用json.dump()将python数据序列化到指定文件中
with open("demo.json", "w") as file_obj:
    json.dump(dict_demo, file_obj)

# 反序列化:使用json.loads()将json字符类型转为python类型
dict_demo = json.loads(json_demo)
print(type(dict_demo))
# 使用json.load()将json字符类型从文件中读出来
with open("demo.json", "r") as file_obj:
    file_date = json.load(file_obj)
    print(file_date)
12.说一说 Redis 的基本类型,每种数据类型的应用场景

string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

string:
hash:
list:
set:
zset:

13.了解 Redis 的事务么?

事务提供了一种"将多个命令打包,一次性提交并按顺序执行"的机制,提交后在事务执行中不会中断。只有在执行完所有命令后才会继续执行来自其他客户的消息。
Redis通过multi,exec,discard,watch实现事务功能。

  1. multi:开始事务
  2. exec:提交事务并执行
  3. discard:取消事务
  4. watch:事务开始之前监视任意数量的键
  5. unwatch:取消WATCH命令对多有key的监控,所有监控锁将会被取消。
    关于ACID:
  6. 单独的隔离操作:事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断
  7. 没有隔离级别的概念:队列中的命令在事务没有被提交之前不会被实际执行
  8. 不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制。
14.了解分布式锁么?

在开发中可能会用到多线程和多进程,如果不同线程或者不同进程抢占同一个资源,对其行读写操作可能会导致数据不一致,导致数据不是在我们预想的情况下改变。这里为了保证线程或者进程安全,python中引入了线程锁和进程锁,保证了数据的一致性和完整性。

而为了保证分布式系统的数据安全,可以使用使用分布式锁来解决这一问题(秒杀场景)。分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。分布式锁的实现有很多种,常见的有redis、zookeeper和数据库mysql等。

15.函数装饰器有什么作用?请列举说明?

装饰器主要是在不修改代码前提下进行功能的扩展,满足面向对象的“开闭原则”。

应用场景:
1,引入日志
2,函数执行时间统计
3,执行函数前预备处理
4,执行函数后清理功能
5,权限校验等场景
6,缓存
7,事务处理

16.Python 垃圾回收机制?
  • 整数

小整数:Python 对小整数的定义是 [-5, 257) 这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,所有位于这个范围内的整数使用的都是同一个对象。单个字母同样也是如此。

大整数:每一个大整数的创建均在内存中会分配一个内存空间,所以大整数的内存空间是需要被回收的。

引用计数为主,标记清除和分代回收为辅:

  • 引用计数:

python里每一个东西都是对象,它们的核心就是一个结构体:PyObject
PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少
当引用计数为0时,该对象生命就结束了。
引用计数机制的优点:

  1. 简单
  2. 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
    引用计数机制的缺点:
  3. 维护引用计数消耗资源
  4. 循环引用
  • 标记清除

『标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。从GCROOT出发,标记所有的可达对象,不可达的就清除掉。
标记清除算法作为Python的辅助垃圾收集技术主要处理的是一些容器对象,比如list、dict、tuple,instance等,因为对于字符串、数值对象是不可能造成循环引用问题。

  • 分代回收

分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。
每个分代集合中索引值越大的代表存活时间越长,越不容易被回收。
分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象

17.魔法函数 __call__怎么使用?

__call__允许一个类的实例像函数一样被调用

#!/usr/bin/python3
# coding=utf-8


class Entity(object):
    def __init__(self, size, x, y):
        self.x, self.y = x, y
        self.size = size

    def __call__(self, x, y):
        # 改变实例属性
        self.x, self.y = x, y

        
if __name__ == '__main__':
    # 创建实例
    demo_obj = Entity(1, 2, 3)
    # 实例可以像函数那样执行,并传入x y值,修改对象的x y
    demo_obj(4, 5)
18.@classmethod 和@staticmethod 用法和区别

@classmethod 是类方法:访问和修改类属性,进行类相关的操作,通过类或示例对象调用,需要传递cls类对象为参数;
@staticmethod 是静态方法:不访问类属性和实例属性,通过类或实例调用,相当于一个普通函数。

19.copy 和 deepcopy 的区别是什么?

copy 仅拷贝对象本身,而不拷贝对象中引用的其它对象。
deepcopy 除拷贝对象本身,而且拷贝对象中引用的其它对象。(子对象)
copy不会为子对象额外创建新的内存空间,当子对象被修改之后,这个子对象的引用都会发生改变;
deepcopy是一个新对象的创建,只是用了和被拷贝对象相同的值,子对象改变不会影响被拷贝对象

20.w、a+、wb 文件写入模式的区别

r : 读取文件,若文件不存在则会报错
w: 写入文件,若文件不存在则会先创建再写入,会覆盖原文件
a : 写入文件,若文件不存在则会先创建再写入,但不会覆盖原文件,而是追加在文件末尾
rb,wb:分别于r,w类似,用于读写二进制文件
r+ : 可读、可写,文件不存在也会报错,写操作时会覆盖
w+ : 可读,可写,文件不存在先创建,会覆盖
a+ :可读、可写,文件不存在先创建,不会覆盖,追加在末尾

21.hasattr() getattr() setattr()的用法

这三种方法用于为对象属性的存在判断、获取和添加修改,简言之就是对象属性的“增、改、查”。

hasattr(object, name):判断对象是否存在name属性
class A():
    name = 'python'
    def func(self):
        return 'A()类的方法func()'


if __name__ == '__main__':
    print(hasattr(A, 'name'))           # True
    print(hasattr(A, 'age'))            # False
getattr(object, name[, default]):获取object对象name属性的值,若没有name属性,则返回default值
class A():
    name = 'python'
    def func(self):
        return 'Hello world'


if __name__ == '__main__':
    print(getattr(A, "name"))       # "python"
    print(getattr(A, "age"))        # Error:class A has no attribute 'age'
    print(getattr(A, "age", 18))    # 18
    print(getattr(A, "func")        # <unbound method A.func>
    print(getattr(A(), "func")()    # 'Hello world',获取到的方法需要实例化后才能调用,类方法则不需要
setattr(object, name, value)object对象的name属性赋值value,如果对象原本存在给定的属性name,则setattr会更改属性的值为给定的balue,如果不存在属性name,会在对象中创建属性并赋值value
class A():
    name = 'python'
    def func(self):
        return 'Hello world'


if __name__ == '__main__':
    setattr(A, 'name', 'java')
    print(getattr(A, 'name'))             # java
    setattr(A, 'age', 20)
    print(getattr(A, "age")               # age
22.请列举你知道的 Python 的魔法方法及用途。

在Python中,所有以 “_ _” 双下划包起来的方法称为“魔法方法”
魔法方法Python解释器自动给出默认的,因此除非需要改变其内部功能,其它时刻刻使用默认魔法方法
最常用三个:"__init__"、"__new__"、"__del__"

__new__是用来创建类并返回这个类的实例,
__init__将传入的参数来初始化该实例,以及初始化示例属性,与__new__共同构成了“构造函数”
__del__将实例化后的对象销毁,即为析构函数
类调用:call

__call__允许一个类像函数一样被调用 
属性访问:__getattr____setattr____delattr__

__getattr__访问对象不存在的属性时,调用该方法,用于定义访问行为
__setattr__设置对象属性时调用
__delattr__删除对象属性时调用
上下文管理器:__enter____exit__

这两个方法请看上面第3题。

迭代器方法:__iter____next__

__iter__:返回一个容器迭代器,很多情况下会返回迭代器,尤其是当内置的iter()方法被调用的时候,以及当使用for x in container:方式循环的时候。迭代器是它们本身的对象,它们必须定义返回self的__iter__方法。
__next__:返回迭代器的下一个元素

23.Python 的传参是传值还是传址?

对可变对象(字典或列表)传址
对不可变对象(数字、字符或元组)传值。

24.什么是猴子补丁?

猴子补丁的含义是指在动态语言中,不去改变源码而对功能进行追加和变更。

为什么叫猴子补丁?

1,这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的,在英文里guerilla发音和gorllia(猩猩)相似,再后来就写了monkey(猴子)。
2,还有一种解释是说由于这种方式将原来的代码弄乱了(messing with it),在英文里叫monkeying about(顽皮的),所以叫做Monkey Patch。
使用协程时,通常在模块头部加入:gevent.monkey.patch_all(),用于将标准库中的thread/socket等给替换掉,这样我们在后面使用socket的时候可以跟平常一样使用,无需修改任何代码,但是它变成非阻塞的了。

总结:猴子补丁就是程序功能的追加或者变更。

网上还有一个例子:

之前做的一个游戏服务器,很多地方用的import json,后来发现ujson比自带json快了N倍,于是问题来了,难道几十个文件要一个个把import json改成import ujson as json吗?
其实只需要在进程startup的地方monkey patch就行了.是影响整个进程空间的.
同一进程空间中一个module只会被运行一次.

import json
import ujson
def monkey_patch_json():
    json.__name__ = 'ujson'
    json.dumps = ujson.dumps
    json.loads = ujson.loads

monkey_patch_json()
print 'main.py',json.__name__
import sub
25.在 Python 中是如何管理内存的?

Python内存池:内存池的概念就是预先在内存中申请一定数量的,大小相等 的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存。这样做最显著的优势就是能够减少内存碎片,提升效率。
python中的内存管理机制——Pymalloc:python中的内存管理机制都有两套实现,一套是针对小对象,就是大小小于256bits时,pymalloc会在内存池中申请内存空间;当大于256bits,则会直接执行new/malloc的行为来申请内存空间。
内存释放参考垃圾回收

26.当退出 Python 时是否释放所有内存分配?

循环引用其它对象或引用自全局命名空间的对象的模块,在 Python 退出时并非完全释放。

27.正则表达式匹配中(.)和(.?)匹配区别?
  1. 什么是贪婪匹配:贪婪匹配在匹配字符串时总是尝试匹配尽可能多的字符。
  2. 什么是非贪婪匹配:与贪婪匹配相反,非贪婪匹配在匹配字符串时总是尝试匹配尽可能少的字符。
  3. Python里数量词默认是贪婪模式的,在"*","?","+","{m,n}"后面加上?,可使贪婪模式变成非贪婪模式。
28.Python 中的作用域(变量的作用域)

L (Local) 局部作用域
E (Enclosing) 闭包函数外的函数中
G (Global) 全局作用域
B (Built-in) 内建作用域
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

30.什么是面向对象的 mro

MRO:Method Resolution Order(方法解析顺序)
MRO就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
MRO 是在Python多继承和钻石继承问题上的核心内容,它规定了如何,什么时候,怎么样去 调用父类的方法

31dir()是干什么用的?

dir()函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;
带参数时,返回参数的属性、方法列表。
如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。

#!/usr/bin/python3
class A(object):
    def f(self):
        print("A.f")


if __name__ == '__main__':
    print(dir())
    # ['A', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
    print(dir(A))
    # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'f']
32 单例模式

单例模式就是确保一个类只有一个实例,当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场,例如一个项目中需要多次连接数据库,单例模式只需要建立一个实例对象(pymysql.connect())。其实python的模块就是天然的单例模式,因为模块在第一次导入时,会生成.pyc文件,当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码。因此只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象
实现单例模式的几种方式:
使用模块
使用装饰器
使用类
使用__new__方法
基于metaclass方法实现

33 __new__和__init__的区别

不同点:

  • __new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是个静态方法
  • __init__是当实例对象创建完成后被调用,然后设置对象属性的一些初始值,通常在初始化一个类实例的时候,是一个实例方法
  • 也就是__new__是当实例对象创建完成后被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数,然后__init__给这个实例设置一些参数,__new__可以进行重写,有返回值
34 python中字符串的反射机制

反射机制就时在运行时,动态的确定对象的类型,并可以通过字符串调用对象属性,方法,导入模块,是一种基于字符串的事件驱动
python中支持反射机制的函数有getattr(),setattr(),delattr(),exec(),eval(),__import__,这些函数都可以执行字符串
hasattr(obj,name):判断一个对象是否有name属性或者name方法,有返回True,否则返回False
getattr(obj,name,defalut=None):获取对象的属性或者方法,如果存在打印出来,否则不打印
setattr(obj,name,values):给对象的属性赋值,若属性不存在则先创建后赋值
delattr(obj,name):删除对应属性

35 生成器与迭代器的区别

迭代器:是一种支持next()操作的对象,它包含了一组元素,当执行next()操作时,返回其中一个元素,当所有元素都被返回后,再执行next()报异常-StopIteration
生成器:生成器本质上就是一个函数,它记住了上一次返回时在函数体中的位置,对生成器函数的第二次(或第n次)调用,跳转到函数上一次挂起的位置,而且记录了程序执行的上下文,生成器不仅’记住’了它的数据状态,生成器还记住了程序执行的位置
区别:

  • 生成器时生成元素的,迭代器时访问集合元素的一种方式
  • 迭代输出生成器的内容
  • 迭代器是一种支持next()操作的对象
  • 迭代器(iterator):其中iterator对象表示的是一个数据流,可以把它看做一个有序序列,但我们不能提前知道序列的长度,只有通过next()函数实现需要计算下一个数据,可以看做生成器的一个子集
36 find和grep

grep命令是一种强大的文本搜索工具,grep搜索内容可以是正则表达式,允许对文本文件进行模式.如果找到匹配模式,grep打印包含模式的所有行
find通常用来在特定的目录下搜索符合条件的文件,也可以用来搜索特定用户属性的文件

37 django对数据查询结果排序怎么做,降序怎么做,查询某个字段怎么做

排序使用order_by()
降序需要在排序字段名前加-
查询字段大于某个值:使用filter(字段名_gt=值)

38 ngnix的正向代理和反向代理

正向代理:是一个位于客户端和原始服务器之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并制定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端,客户端必须要进行一些特别的设置才能使用正向代理
反向代理:正好相反,对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特比的设置,客户端向反向代理的命名空间中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是它自己的一样

39 django本身提供了runserver,为什么不能用来部署

runserver方法是调试django时经常用到的运行方式,它使用django自带的WSGI Server运行,主要在测试和开发中使用,并且runserver开启的方式也是单进程。uwsgi是一个web服务器,它实现了WSGI协议,uwsgi,http等协议。注意uwsgi是一种通信协议,而uWSGI是实现uwsgi和WSGI协议的web服务器。uWSGI具有超快的性能、低内存占用和多app管理等优点,并且搭配着nginx就是一个生产环境了,能够将用户请求与应用app隔离开,实现真正的部署,相比来讲,支持的并发量更高,方便管理多进程,发挥多核的优势,提升性能

40 数据库的引擎有哪些 它们的区别

引擎:InnoDB MyISAM MEMORY
InnoDB:支持事务和外键,可以进行回滚提交等操作,适合写操作多的
MyISAM:默认引擎,不支持事务和外键,但是访问速度快,适合读操作多的
MEMORY:数据放在内存中,默认使用HASH索引,但是服务器一旦关闭,数据就会丢失,但是表还会继续存在

41 数据库优化思路
  • 优化索引、SQL语句、分析慢查询
  • 设计表的时候严格根据数据库的设计范式来设计数据库
  • 使用缓存,把经常访问到的数据而且不需要经常变化的数据放在缓存中,能节约磁盘IO
  • 优化硬件,采用SSD,使用磁盘队列技术
  • 采用MySQL内部自带的表分区技术,把数据分成不同的文件,能够提高磁盘的读取效率
  • 垂直分表;把一些不经常读的数据放在一张表中,节约磁盘I/O
  • 主从分离读写;采用主从复制把数据库的读操作和写入操作分离开来
  • 分库分表分机器(数据量特别大),主要的原理就是数据路由
  • 选择合适的表引擎,参数上的优化
  • 进行架构级别的缓存,静态化和分布式
  • 不采用全文索引
  • 采用更快的存储技术,例如NoSQL存储经常访问的数据
42 简述FBV和CBV

FBV:就是在视图里使用函数处理请求
CBV:就是在视图里使用类处理请求

43 什么是中间件并简述其作用

中间是一个用来处理django的请求和响应的框架级别的钩子,他是一个轻量、低级别的插件系统,用于在全局范围内改变django的输入和输出,每个中间件组件都负责做一些特定的功能
中间件介于request和response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入和输出

44 常用视图响应的方式

视图响应:HttpResponse
json数据:JsonResponse
重定向:redirect

45 values()和values_list()有什么区别

values:取字典的queryset
values_list:取元素的queryset

46 解释blank和null

null是针对数据库而言,如果null=True,表示该数据库的字段可以为空
blank是针对表单的,如果blank=True,表示你的表单填写该字段的时候可以不填

47 WSGI / uwsgi/ uWSGI区分

WSGI:web服务器网关接口,它不是服务器,python模块,框架,api或者任何软件,只是一种描述web服务器如何与web应用程序通信的规范
uWSGI:是一个全功能的http服务器,实现了WSGI协议、uwsgi协议、http协议等。它要做的就是把HTTP协议转化成语言支持的网络协议。比如把HTTP协议转化成WSGI协议,让Python可以直接使用
uwsgi: 与WSGI一样,是uWSGI服务器的独占通信协议,用于定义传输信息的类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值