python面试题

断言和异常

  1. 什么是断言?应用场景?
    Python的assert用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。

    x = 23
    assert x > 0, "x is not zero or negative"
    assert x%2 == 0, "x is not an even number"
    

    在这里插入图片描述
    按约定设计的目标是为了正确的编程,前置条件和后置条件是需要保持的。这是断言的典型应用场景,因为一旦我们发布了没有问题的代码到产品中,程序会是正确的,并且我们能安全的移除检查。
    如果约定被函数或调用这破坏,代码就会出问题。我们说函数有一些前置条件和后置条件,所以函数就会这么写:

    def first_upper(astring):
        assert isinstance(astring, str) and len(astring) > 0
        result = astring[0].upper()
        assert isinstance(result, str) and len(result) == 1
        assert result == result.upper()
        return result
    
  2. 与异常的区别
    异常被捕获后可以不作处理,程序从捕获位置继续执行。
    而断言是完全无法忽略的,程序在断言失败处立即终止。

    因此断言通常用于调试版本,用来发现程序中的逻辑错误。虽然异常也能起到这样的作用,但是不应该用异常代替断言。

    异常用于处理正确程序中的运行期问题(比如内存分配失败,窗口创建失败,线程创建失败,打开文件失败),以尽可能恢复,而不是终止程序。对于运行异常,使用断言是非常不合适的,理由很显然:

    1. 断言在发布版不起作用;
    2. 断言的处理方式不够友好;
    3. 运行异常不是程序错误,没有必要报告源代码出错位置;

json.dumps会将中文转换为unicode编码后保存怎么解决

  1. ensure_ascii=False就解决了问题
  2. 平常使用json.dumps(target,ensure_ascii=False)
  3. 在django中的JsonResponse也可以加ensure_ascii=False的参数,但与平常稍微有点不同(详细ctrl进去看JsonResponse源码,这里不再赘述)

select、poll、epoll 模型的区别(基础)

  1. select==>时间复杂度O(n)
    它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。
    所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。
  2. poll==>时间复杂度O(n)
    poll本质上和select没有区别,也是无差别轮询所有流,找出能读出数据或者写入数据的流, 但是它没有最大连接数的限制,原因是它是基于链表来存储的。
  3. epoll==>时间复杂度O(1)
    epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们(异步回调)。

什么是cdn

  1. CDN最初的核心理念,就是将内容缓存在终端用户附近。
    内容源不是远么?那么,我们就在靠近用户的地方,建一个缓存服务器,把远端的内容,复制一份,放在这里,不就OK了?
    在这里插入图片描述
    因为这项技术是把内容进行了分发,所以,它的名字就叫做CDN——Content Delivery Network,内容分发网络。

  2. 而且还需要注意的是,CDN并不是只能缓存视频内容,它还可以对网站的静态资源(例如各类型图片、html、css、js等)进行分发,对移动应用APP的静态内容(例如安装包apk文件、APP内的图片视频等)进行分发。
    如果某个用户想要访问优酷的视频点播内容,那么:
    在这里插入图片描述
    具体步骤:

    ①、当用户点击APP上的内容,APP会根据URL地址去本地DNS(域名解析系统)寻求IP地址解析。

    ②、本地DNS系统会将域名的解析权交给CDN专用DNS服务器。

    ③、CDN专用DNS服务器,将CDN的全局负载均衡设备IP地址返回用户。

    ④、用户向CDN的负载均衡设备发起内容URL访问请求。

    ⑤、CDN负载均衡设备根据用户IP地址,以及用户请求的内容URL,选择一台用户所属区域的缓存服务器。

    ⑥、负载均衡设备告诉用户这台缓存服务器的IP地址,让用户向所选择的缓存服务器发起请求。

    ⑦、用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。

    ⑧、如果这台缓存服务器上并没有用户想要的内容,那么这台缓存服务器就要网站的源服务器请求内容。

    ⑨、源服务器返回内容给缓存服务器,缓存服务器发给用户,并根据用户自定义的缓存策略,判断要不要把内容缓存到缓存服务器上。

  3. CDN的好处
    采用CDN技术,最大的好处,就是加速了网站的访问——用户与内容之间的物理距离缩短,用户的等待时间也得以缩短。

简述数据三大范式

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

    第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。

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

    第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。

  3. 第三范式(确保每列都和主键列直接相关,而不是间接相关)

    第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

sql主键和外键的区别

1、主键是唯一标识一条记录,不能有重复,不允许为空,而外键可以重复,可以是空值;
2、主键是用来保持数据完整性,外键是用来建立与其他表联系用的;
3、主键只有一个,外键可以有多个。
4、主键只有一个,不能重复也不允许有空值而外键可以有多个,可以重复也可以有空值;主键是用来保持数据完整性的,外键是用来与其他表建立联系的

mysql常见函数

MySQL 数值型函数

MySQL 	数值函数

ABS		求绝对值
SQRT	求二次方根
MOD		求余数
CEIL 	两个函数功能相同,都是返回不小于参数的最小整数,即向上取整
FLOOR	向下取整,返回值转化为一个BIGINT
RAND	生成一个0~1之间的随机数,传入整数参数是,用来产生重复序列
ROUND	对所传参数进行四舍五入
SIGN	返回参数的符号
POW 	两个函数的功能相同,都是所传参数的次方的结果值
SIN		求正弦值
ASIN	求反正弦值,与函数 SIN 互为反函数
COS		求余弦值
ACOS	求反余弦值,与函数 COS 互为反函数
TAN		求正切值
ATAN	求反正切值,与函数 TAN 互为反函数
COT		求余切值

MySQL 	字符串函数

LENGTH	计算字符串长度函数,返回字符串的字节长度
CONCAT	合并字符串函数,返回结果为连接参数产生的字符串,参数可以使一个或多个
INSERT		替换字符串函数
LOWER		将字符串中的字母转换为小写
UPPER		将字符串中的字母转换为大写
LEFT		从左侧字截取符串,返回字符串左边的若干个字符
RIGHT		从右侧字截取符串,返回字符串右边的若干个字符
TRIM		删除字符串左右两侧的空格
REPLACE		字符串替换函数,返回替换后的新字符串
SUBSTRING	截取字符串,返回从指定位置开始的指定长度的字符换
REVERSE		字符串反转(逆序)函数,返回与原始字符串顺序相反的字符串

MySQL 日期和时间函数

CURDATE (CURRENT_DATE)	两个函数作用相同,返回当前系统的日期值
CURTIME (CURRENT_TIME)	两个函数作用相同,返回当前系统的时间值
NOW						返回当前系统的日期和时间值
UNIX_TIMESTAMP			获取UNIX时间戳函数,返回一个以 UNIX 时间戳为基础的无符号整数
FROM_UNIXTIME			将 UNIX 时间戳转换为时间格式,与
MONTH					获取指定日期中的月份
MONTHNAME				获取指定日期中的月份英文名称
DAYNAME					获取指定曰期对应的星期几的英文名称
DAYOFWEEK				获取指定日期对应的一周的索引位置值
WEEK					获取指定日期是一年中的第几周,返回值的范围是否为 052153
DAYOFYEAR				获取指定曰期是一年中的第几天,返回值范围是1~366
DAYOFMONTH				获取指定日期是一个月中是第几天,返回值范围是1~31
YEAR					获取年份,返回值范围是 19702069
TIME_TO_SEC				将时间参数转换为秒数
SEC_TO_TIME				将秒数转换为时间
DATE_ADD 和 ADDDATE		两个函数功能相同,都是向日期添加指定的时间间隔
DATE_SUB 和 SUBDATE		两个函数功能相同,都是向日期减去指定的时间间隔
ADDTIME					时间加法运算,在原始时间上添加指定的时间
SUBTIME					时间减法运算,在原始时间上减去指定的时间
DATEDIFF				获取两个日期之间间隔,返回参数 1 减去参数 2 的值
DATE_FORMAT				格式化指定的日期,根据参数返回指定格式的值
WEEKDAY					获取指定日期在一周内的对应的工作日索引

为什么使用TCP/IP四层而不用OSI七层模型

在这里插入图片描述

  1. TCP/IP模型早于OSI模型
  2. OSI只适合作为理论概念
  3. OSI 自身也有缺陷,其中会话层和表示层几乎是空的,而数据链路层和网络层包含内容太多,有很多的子层插入,每个子层都有不同的功能。OSI 模型以及相应的服务定义和协议都极其复杂,有些功能,如:编址、流控制和差错控制,都会在每一层上重复出现,这必然会降低系统效率。

一行打印九九乘法表

print("\n".join(" ".join([f"{y}X{x}={x * y}" for y in range(1, x + 1)]) for x in range(1, 10)))

对比理解:

for x in range(1, 10):
    for y in range(1, x + 1):
        print(f'{y}X{x}={x * y:2}', end=' ')
        if y == x:
            print()

def func(a,b=[]) 这种写法有什么坑?

def func(a,b=[]):
    b.append(a)
    print(b)
func(1)
func(1)
func(1)
func(1)

结果---------------
[1]
[1, 1]
[1, 1, 1]
[1, 1, 1, 1]

函数的第二个默认参数是一个list,当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储,所以每次执行就会append进去一个1,默认参数应该设置为None。
在这里插入图片描述

post请求可以通过url传递参数吗?像get请求一样

URL传参数无论是用GET还是POST都是可以的,只是POSt还多了更多数据传输通道(还可以传更多数据,而不受URL长度限制),而且利用URL传参的格式是统一的,不区分GET和POST。

threading.local的作用?

hreading.local()这个方法的特点用来保存一个全局变量,但是这个全局变量只有在当前线程才能访问,如果在开发多线程应用的时候 需要每个线程保存一个单独的数据供当前线程操作,可以考虑使用这个方法,简单有效。

举例:每个子线程使用全局对象a,但每个线程定义的属性a.xx是该线程独有的,Python提供了 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据其它线程不可见(本质上就是不同的线程使用这个对象时为其创建一个独立的字典)。

内部自动为每个线程维护一个空间(字典),用于当前存取属于自己的值。保证线程之间的数据隔离。

主要的目的是线程之间的数据隔离。
当然,自己写也不是不可以,但开发的一个宗旨是不必重复造轮子。

import time
import threading

local = threading.local()

def func(n):
    print(threading.current_thread())
    local.val = n
    time.sleep(2)

    print(n)

for i in range(10):
    t = threading.Thread(target=func,args=(i,))
    t.start()

flask的请求上下文中就实现了一个theading.local(),于是每一个用户都可以拿到自己的请求和session对象

{
'theading_1(线程号)':
	{
		'request':Request(),
		'session':Session(),
	}
,
'theading_2(线程号)':
	{
		'request':Request(),
		'session':Session(),
	}
}

Redis 6种内存淘汰策略:

1、noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
2、allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个比较常用)
3、allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
4、volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
5、volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
6、volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。

Redis 中如何实现的消息队列?实现的方式有几种?

  1. List 类型实现的方式最为简单和直接,它主要是通过 lpush、rpop 存入和读取实现消息队列的

    127.0.0.1:6379> lpush mq "java" #推送消息 java
    (integer) 1
    127.0.0.1:6379> lpush mq "msg" #推送消息 msg
    (integer) 2
    127.0.0.1:6379> rpop mq #接收到消息 java
    "java"
    127.0.0.1:6379> rpop mq #接收到消息 msg
    "mq"
    
  2. 在 Redis 2.0 之后 Redis 就新增了专门的发布和订阅的类型,Publisher(发布者)和 Subscriber(订阅者)来实现消息队列

为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。

保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候,服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Generalzy

文章对您有帮助,倍感荣幸

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值