Loading

Python全栈面试题及知识点总结

Python全栈面试题

Python全栈阶段总结:https://github.com/HkwJsxl/PythonFullStack/tree/master/Notes

Python基础

基础

逻辑运算

v2 = "wupeiqi" and "alex"

# 第一步:将and前后的只转换为布尔值 True and True
# 第二步:判断本次操作取悦于谁?由于前面的是True,所以本次逻辑判断取决于后面的值。
# 所以,后面的只等于多少最终结果就是多少。 v2 = "alex"

v3 = "" and "alex"
# 第一步:将and前后的只转换为布尔值 False and True
# 第二步:判断本次操作取悦于谁?由于前面的是False,所以本次逻辑判断取决于前面的值。
# 所以,前面的只等于多少最终结果就是多少。 v2 = ""

v4 = 1 or 8 
# 第一步:将and前后的只转换为布尔值 True or True
# 第二步:判断本次操作取悦于谁?由于前面的是True,所以本次逻辑判断取决于前面的值。
# v4 = 1

v5 = 0 or 8 
# 第一步:将and前后的只转换为布尔值 False or True
# 第二步:判断本次操作取悦于谁?由于前面的是False,所以本次逻辑判断取决于后面的值。
# v5 = 8

# or,看第一个值,如果第一个值为真,结果就应该是第一个值,否则就结果就是第二个值。
# and,看第一个值,如果第一个值真,结果就应该是第二个值,否则结果就是第一个值。

元组的定理

如何体现不可变呢?
记住一句话:《"我儿子永远不能换成是别人,但我儿子可以长大"》

位运算

v1 = 10 >> 1 
print(v1) # 值为5

函数传参

# 请问Python的参数**默认**传递的是什么?
函数执行传参时,传递的是内存地址。

# 函数的参数传递的是引用(内存地址)还是值(拷贝一份)?
**函数的参数传递默认是传递的内存地址**
**在有动态参数的时候时把值添加给args和kwargs,相当于拷贝一份**(可理解为内部循环每个元素并设置到args和kwargs中)

# Python参数的这一特性有两个好处:
- 节省内存
- 对于可变类型且函数中修改元素的内容,所有的地方都会修改。可变类型:列表、字典、集合。

# 注意:int,str不会开辟新的内存地址,Python内部的内存驻留机制会使用原有的已开辟的内存地址

参数的默认值

def func(a1,a2=18):
    print(a1,a2)
    
# 原理:Python在创建函数(未执行)时,如果发现函数的参数中有默认值,则在函数内部会创建一块区域并维护这个默认值。
# 执行函数未传值时,则让a2指向 函数维护的那个值的地址。
# 执行函数传值时,则让a2指向新传入的值的地址。

在特定情况【默认参数的值是可变类型 list/dict/set】 & 【函数内部会修改这个值】下,参数的默认值 有坑 。

  • # 在函数内存中会维护一块区域存储 [1,2,666,666,666] 100010001
    def func(a1,a2=[1,2]):
        a2.append(666)
        print(a1,a2)
    
    # a1=100
    # a2 -> 100010001
    func(100) # 100  [1,2,666]
    
    # a1=200
    # a2 -> 100010001
    func(200) # 200 [1,2,666,666]
    
    # a1=99
    # a2 -> 1111111101
    func(99,[77,88]) # 66 [177,88,666]
    
    # a1=300
    # a2 -> 100010001
    func(300) # 300 [1,2,666,666,666] 
    
  • 大坑

    # 在内部会维护一块区域存储 [1, 2, 10, 20,40 ] ,内存地址 1010101010
    def func(a1, a2=[1, 2]):
        a2.append(a1)
        return a2
    
    # a1=10
    # a2 -> 1010101010
    # v1 -> 1010101010
    v1 = func(10)
    print(v1) # [1, 2, 10]
    
    # a1=20
    # a2 -> 1010101010
    # v2 -> 1010101010
    v2 = func(20)
    print(v2) # [1, 2, 10, 20 ]
    
    # a1=30
    # a2 -> 11111111111        [11, 22,30]
    # v3 -> 11111111111
    v3 = func(30, [11, 22])
    print(v3) #  [11, 22,30]
    
    # a1=40
    # a2 -> 1010101010
    # v4 -> 1010101010
    v4 = func(40)
    print(v4) # [1, 2, 10, 20,40 ] 
    
  • 深坑

    # 内存中创建空间存储 [1, 2, 10, 20, 40] 地址:1010101010
    def func(a1, a2=[1, 2]):
        a2.append(a1)
        return a2
    
    # a1=10
    # a2 -> 1010101010
    # v1 -> 1010101010
    v1 = func(10)
    
    
    # a1=20
    # a2 -> 1010101010
    # v2 -> 1010101010
    v2 = func(20)
    
    # a1=30
    # a2 -> 11111111111   [11,22,30]
    # v3 -> 11111111111
    v3 = func(30, [11, 22])
    
    # a1=40
    # a2 -> 1010101010
    # v4 -> 1010101010
    v4 = func(40)
    
    print(v1) # [1, 2, 10, 20, 40]
    print(v2) # [1, 2, 10, 20, 40]
    print(v3) # [11,22,30]
    print(v4) # [1, 2, 10, 20, 40] 
    

列表推导式

"""1.1"""
data_list = [lambda x: x + i for i in range(10)]  # [函数,函数,函数]   i=9
v1 = data_list[0](100)
v2 = data_list[3](100)
print(v1, v2)  # 109 109
"""1.2"""
def num():
    return [lambda x: i * x for i in range(4)]
# 1. num()并获取返回值  [函数,函数,函数,函数] i=3
# 2. for循环返回值
# 3. 返回值的每个元素(2)
result = [m(2) for m in num()]  # [6,6,6,6]
print(result)
"""1.3"""
def num():
    return (lambda x: i * x for i in range(4))
# 1. num()并获取返回值  生成器对象
# 2. for循环返回值
# 3. 返回值的每个元素(2)
result = [m(2) for m in num()]  # [0,2,4,6]
print(result)
"""总结:可以简单的看为[]for已经执行完了,()是传进去后对应每个值执行"""

# 一副扑克牌
poker_list = [[color, num] for color in ["红桃", "黑桃", "方片", "梅花"] for num in range(1, 14)]
print(poker_list)

其他

深浅拷贝

深浅拷贝只针对于可变类型,不可变类型无意义,不可变类型永远不会拷贝

  • 浅拷贝

    不可变类型,不拷贝
    可变类型:只拷贝第一层
    值拷贝,源数据发生改变时,浅拷贝对象一起发生改变
    
  • 深拷贝

    不可变类型,不拷贝
    	特殊:元组,元组中有可变类型时,拷贝元组
    可变类型:拷贝所有层的可变类型或含有可变类型的元组
    内存地址的拷贝,源数据发生改变时,深拷贝对象不会发生改变
    

可哈希和不可哈希类型

1.哈希类型,即在原地不能改变的变量类型,不可变类型。
数字类型,字符串,元组,布尔,冻结集合(frozenset),None
2.原地可变类型:list、dict和set。它们不可以作为字典的key,也不可以嵌套在集合中。
set是可变类型
frozenset是不可变类型

简述解释性语言和编译性语言的区别

解释性语言:Java、Python、Perl、JavaScript、VBScript、Ruby、MATLAB等。
编译性语言:C/C++、Pascal/Object Pascal(Delphi)等。
解释性语言:
   解释性语言的程序不需要编译,省了道工序,解释性语言在运行程序的时候才翻译,比如解释性java语言,专门有一个解释器能够直接执行java程序,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就要翻译一次,效率比较低。
编译性语言:
   编译型语言写的程序执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,以后要运行的话就不用重新翻译了,直接使用编译的结果就行了(exe文件),因为翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高。

py2和py3的区别

Python 2 中,隐式 str 类型是 ASCII。
但是在 Python 3.x 中,隐式 str 类型是 Unicode。Python 2.x 也支持 Unicode 

"""错误处理"""
# Python2:
try:
    trying_to_check_error
except NameError, err: # 在Python 3.x中不支持
    print err, 'Error Caused' 
# Python3:
try:
     trying_to_check_error
except NameError as err: # 'as'在Python 3.x中使用
     print (err, 'Error Caused')
        
"""多个模块被改名"""
ConfigParser===configparser
SocketServer===socketserver

"""类的继承"""
创建类时,py2分为经典类和新式类,新式类就是继承object的类,经典类是没有继承的类,而py3中全部是新式类,默认继承object。
在属性查找时,经典类查找方式为深度优先,新式类是广度优先。仅py3中有类的mro函数方法,输出继承父类的顺序列表。

py2和py3默认解释器编码

py2:ascii
py3:utf-8
# 如何在代码中修改解释器的编码?
在文件的顶部加一句: # -*- coding:编码 -*-

GIL全局解释器锁

"""GIL并不是Python的特性,而是Cpython的特性,Python完全可以不依赖于GIL"""

在CPython解释器中GIL是一把互斥锁,用来阻止同一个进程下的多个线程的同时执行,同一个进程下的多个线程无法利用多核优势
GIL是保证解释器级别的数据的安全
GIL会导致同一个进程下的多个线程无法同时执行(无法利用多核优势)
针对不同的数据还是需要加不同的锁处理
解释型语言的通病:同一个进程下多个线程无法利用多核优势

计算密集型:
	多进程好一些
IO密集型:
	多线程更加节省资源

简述ascii、unicode、utf-8、gbk编码

# ascii编码、unicode字符集、utf-8编码、gbk编码本质上都是字符与二进制的关系。
- ascii,只有256种对照关系,只包含英文、符号等。
- unicode,万国码,包含了全球所有文字和二进制之间的一个对应关系。(ucs2或ucs4)
- utf-8,对unicode字符集的码位进行压缩处理,间接也维护了字符和二进制的对照表。
- gbk,包含中国、日本韩国等亚洲国家的文字和二进制的对照表。

__pycache__里面存放了些文件,怎么产生的

字节码文件

计算机不能识别python源代码,所以python解释器在运行py文件时,会先完成模块的加载和链接,
编译成字节码文件,写入内存中,供cpu读取,
从内存中读取字节码文件并执行,完事之后再将字节码文件写入硬盘中,
之后若再次运行此py文件,先检查本地是否有对应的字节码文件和字节码文件的修改时间是否在脚本文件的时间之后,
是的话就执行,否则重复上述步骤
    
第一次执行代码时,python解释器将编译的结果存放到pycache文件中,下次在运行时,如果被调用的模块未发生改变,就直接运行已有的字节码文件,不再重新的编译,节省了资源和时间。

Python面向对象

简述面向对象的三大特性

封装
    将一些属性或方法封装到类里面,可供外部调用或隐藏
    封装原则:高内聚,低耦合
继承
    将子类的数据封装到父类中,供子类使用,将多个子类的方法封装到同一类型中,提高代码重用性
多态
    本身具有多态特性,提倡鸭子类型,不在乎传入的参数是什么类型,只要有对应的方法即可

经典类和新式类

py2中分为经典类(不继承Object)和新式类(继承Object)
py3中都是新式类(默认都会继承Object)

经典类是深度优先
新式类是广度优先

在类中 @staticmethod@classmethod的作用是什么?

"""
两者都不需要传入self参数,都不用通过实例化去调用方法(类名.方法())
@classmethod
    修饰类方法,第一个参数为cls,值为当前调用的对象本身
@staticmethod
    修饰静态方法,可以没有参数,相当于在类中定义一个普通的函数
"""

简述你理解的:迭代器、生成器、可迭代对象。

"""
迭代器
    拥有__iter__,__next__方法,
    并且__iter__返回迭代器对象本身,即self,__next__返回下一个数据,如果没有了,要抛出StopIteration异常
生成器
    同样拥有__iter__,__next__方法,生成器类似一种特殊的迭代器类
可迭代对象
    拥有__iter__方法,并且该方法返回一个迭代器对象,
    可迭代对象可通过for循环取值,在循环内部先执行__iter__方法,取出其迭代器对象,再通过next功能逐步取值
"""

迭代器带来的好处是什么

占用内存小,可以方便的for循环读取值

代码题

写出结果

def func(item, request=[]):
    request.append(item)
    print(request)
func({"method": "get"})
func({"method": "post"})
"""
结果:
[{"method": "get"}]
[{"method": "get"},{"method": "post"}]
"""

列表循环删除

# 错误方式, 有坑,结果不是你想要的。
user_list = ["刘的话", "范德彪", "刘华强", '刘尼古拉斯赵四', "宋小宝", "刘能"]
for item in user_list:
    if item.startswith("刘"):
        user_list.remove(item)
print(user_list)

# 正确方式,倒着删除。
user_list = ["刘的话", "范德彪", "刘华强", '刘尼古拉斯赵四', "宋小宝", "刘能"]
for index in range(len(user_list) - 1, -1, -1):
    item = user_list[index]
    if item.startswith("刘"):
        user_list.remove(item)
print(user_list)

斐波那契数列

def fib(max_count):
    first_val = 1
    second_val = 0
    count = 0
    while count < max_count:
        next_val = first_val + second_val
        first_val = second_val
        second_val = next_val
        yield next_val
        count += 1
count = input("请输入要生成斐波那契数列的个数:")
count = int(count)
fib_generator = fib(count)
for num in fib_generator:
    print(num)

手写单例

from threading import Thread, RLock
class Singleton:
    instance = None
    rlock = RLock()
    def __init__(self, name):
        self.name = name
    def __new__(cls, *args, **kwargs):
        with cls.rlock:
            if cls.instance:
                return cls.instance
            cls.instance = object.__new__(cls)
        return cls.instance

MySQL

关系型和非关系型数据库区别

关系型:支持常用的sql语句,本质相当于一个二维表模型,表之间可以有关联、外键等
非关系型:可以有多种的状态的命令,k、v键值对等,支持高并发,效率高,可用于集群的分布式均衡负载

MySQL数据库事务特性有哪些

四大特性:
    原子性:不可分割,要么都成功,要么都失败回滚
    一致性:事务执行前后数据完整性一致
    隔离性:事务执行中,不受到外界的干扰
    持久性:事务执行结束,数据持久到数据库中

通俗地讲一下三个范式

范式一:记录的原子性,不可拆分
范式二:唯一性
范式三:冗余性

为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。
在实际开发中最为常见的设计范式有三个:

1.第一范式(确保每列保持原子性)

第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。
上表所示的用户信息遵循了第一范式的要求,这样在对用户使用城市进行分类的时候就非常方便,也提高了数据库的性能。

2.第二范式(确保表中的每列都和主键相关)

第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。
订单信息表
这样就产生一个问题:这个表中是以订单编号和商品编号作为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。所以在这里违反了第二范式的设计原则。
而如果把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中,就非常完美了。如下所示。
这样设计,在很大程度上减小了数据库的冗余。如果要获取订单的商品信息,使用商品编号到商品信息表中查询即可。

3.第三范式(确保每列都和主键列直接相关,而不是间接相关)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下面这两个表所示的设计就是一个满足第三范式的数据库表。
这样在查询订单信息的时候,就可以使用客户编号来引用客户信息表中的记录,也不必在订单信息表中多次输入客户信息的内容,减小了数据冗余。

主键、外键和索引的区别

1.概念
主键:唯一标识一条记录,不能有重复,不允许为空。
外键:表的外键是另一表的主键,外键可以有重复,可以是空值。
索引:该字段没有重复值,但可以有一个空值。
2.作用
主键:用来保证数据完整性
外键:用于和其他表建立联系用的
索引:提高查询排序的速度
3.个数
主键:主键只能有一个
外键:一个表可以有多个外键
索引:一个表可以有多个唯一索引

commit和rollback的理解

commit:sql执行成功,数据提交到数据库中
rollback:sql执行失败,不会提交到数据库,数据回滚到执行sql之前

SQL语句查询优化有哪些方法

建立索引并命中索引,在查询的时候,要尽量让数据库引擎使用索引。加入explain执行计划

1.尽量避免使用select *
2.尽量避免使用!=
3.尽量避免使用or
	优化方式:可以用union代替or。如下:
    SELECT * FROM t WHERE username="hkw"
    UNION
    SELECT * FROM t WHERE nickname="jon"
4.尽量避免使用in和not in
	优化方式:如果是连续数值,可以用between代替
    如果是子查询,可以用exists代替。如下:
	SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t1.username = t2.username)
5.尽量避免在字段开头模糊查询
	SELECT * FROM t WHERE username LIKE '%li%'
    优化方式:尽量在字段后面使用模糊查询。如下:
    SELECT * FROM t WHERE username LIKE 'li%'
6.尽量避免进行null值的判断
    SELECT * FROM t WHERE score IS NULL
    优化方式:可以给字段添加默认值0,对0值进行判断。如下:
    SELECT * FROM t WHERE score = 0
7.尽量避免在where条件中等号的左侧进行表达式、函数操作
	SELECT * FROM t2 WHERE score/10 = 9
    SELECT * FROM t2 WHERE SUBSTR(username,1,2) = 'li'
    优化方式:可以将表达式、函数操作移动到等号右侧。如下:
    SELECT * FROM t2 WHERE score = 10*9
    SELECT * FROM t2 WHERE username LIKE 'li%'

前端

http协议

http协议特性

1.基于TCP/IP协议
http协议是基于TCP/IP协议之上的应用层协议。

2.基于请求-响应模式
HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并返回。

3.无状态保存
HTTP是一种不保存状态,即无状态(stateless)协议。

4.无连接
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

JS

基础

js基本数据类型
undefined,null,number,string,symbol,boolean,object,array,date
js中的拷贝(深浅拷贝)
https://www.cnblogs.com/echolun/p/7889848.html
https://www.bilibili.com/video/BV1iu411e7DS/?spm_id_from=333.337.search-card.all.click&vd_source=69181b959bc0cae8de15caffd47134a6
数组方法有哪些
push,shift,unshift,isArray,indexOf,forEach
数组去重的方法
var arr = [1, 2, 35, 35, '香风智乃', '香风智乃', '雏鹤爱']
new Set(arr);
判断是否是整数
Number.isInteger(num)
this指向
全局的this指向什么
	window对象
对象中的this指向什么
	当前对象
事件中this指向什么
	当前事件触发的元素本身
简述css盒子模型
可以把标签看作是一个盒子,包括几大部分:内容,padding,border,margin

其他

JS预编译
<script>
    var a = 10;
    console.log(a);

    function foo(a) {
        console.log("a1", a);
        var a = 100;
        console.log(a);

        function a() {
        }

        console.log(a);
        var b = function () {
        };
        console.log("b1", b);

        function d() {
        }
    }

    var c = function () {
        console.log("匿名函数C");
    };
    console.log(c);
    foo(20);
</script>
<script>
    console.log("------")
    var num3 = 10;

    function func3() {
        console.log(num3);
        var num3 = 20;
    }

    func3();
    console.log(num3);

</script>
循环绑定事件
<ul class="lis">
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>
// 循环绑定事件

var eles = document.querySelectorAll(".lis li");
// console.log(eles);

for (var i = 0; i < eles.length; i++) {
    console.log(eles[i]);
    eles[i].onclick = function () {
        // console.log(eles[i].innerHTML);  // 坑
        console.log(this.innerHTML);

    }
}

console.log("i:", i);
posted @ 2023-03-03 17:09  hkwJsxl  阅读(258)  评论(0)    收藏  举报