去年也是这个时候吧,当时正好也是面试,所以总结了三篇面试的题目。另外前段时间我出了一个面试题的课程Python 面试题 170 道:2019 版,总结了Python的一些方法的使用技巧以及在面试中可能遇到的题目。接下来是我这这段时间遇到的面试题,之前一直懒得写,今天做一个总结吧,这里的题目是170道面试题中没有出现的题目。

1.简述cookie和session的区别

这篇文章写的很详细了:https://mp.weixin.qq.com/s/rIiC-yVzm1swR8rOioP2QA

2.网络状态码:

状态码 类别 原因
1XX Informational(信息性状态码) 接受的请求正在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirection(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求出错

3.状态码301和302是什么含义,其区别是?

定义

301 Moved Permanently 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。

302 Found 请求的资源现在临时从不同的URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。

简单理解就是301是永久重定向,301请求是可以缓存的,即通过看status code,可以发现后面写着from cache。而302是临时重定向。

区别

302重定向只是暂时的重定向,搜索引擎会抓取新的内容而保留旧的地址,因为服务器返回302,所以,搜索搜索引擎认为新的网址是暂时的。

而301重定向是永久的重定向,搜索引擎在抓取新的内容的同时也将旧的网址替换为了重定向之后的网址。

4.正则表达式相关的题目

1.在网页中使用正则表达式匹配出类似https://m.baidu.com/1.html的链接。例如https://m.baidu.com/22.html可以但是https://m.baidu.com不可以。
答:这个比较简单直接.*就解决了

import re

html = ("""
<div>
   <a href='https://m.baidu.com/1.html'> 
   这是页面1
   </a>
   <a href='https://m.baidu.com'> 
   这是页面2
   </a>
   <a href='https://m.baidu.com/music.html'> 
   这是页面3
   </a>
   <a href='https://m.yahoo.com/music.html'> 
   这是页面4
   </a>
   <a href='https://m.baidu.com/music_html_9.html'>这是页面5</a> <a href='https://m.baidu.com/music_html_8.html'> 
   这是页面6
   </a>
</div>
""")
pattern_str = r"https://m.baidu.com/.*?\.html"
pattern_obj = re.compile(pattern_str)
result = pattern_obj.findall(html)
print(result)

2.思考上面的.*?能否改为.*为什么?
这就牵扯到贪婪匹配和懒惰匹配;在限定符后面加上?,则为懒惰模式;在限定符后面不加?则为贪婪模式。

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。
懒惰限定符

代码/语法 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

所以针对第一题如果我们使用.*匹配最后一条会匹配出如下内容

 "https://m.baidu.com/music_html_9.html'>这是页面5</a> <a href='https://m.baidu.com/music_html_8.html"

为了避免这种情况我们使用.*?解决问题。同时需要注意的是我们匹配的结尾是.html
而不是html,这就是为什么我写成.?\.html而不是.?html了。

5.写一个装饰器tag满足下面的要求:

@tag
def render(text, *args, **kwargs):
    return text

@tag(name = 'p', title = 'text'):
def render2(text, *args, **kwargs):
    return text

print(render("Hello"))
print(render2("Hello"))

答:
关于装饰器的文章,网上很多资料了,我就不走他们的套路了。
我就写写我理解。先看代码

def A(func):
   def wrapper():
       print("in A")
       func()
   return wrapper

@A
def B():
   print("in B")

上面被装饰A修饰B内部实际等价于下面这句

B = A(B) 

也就是说,使用装饰器B在被调用的时候实际是调用了函数A的别名而已。
但是如果B含有参数就出错了。
像这种

def A(func):         (1)
   def wrapper():    (2)
       print("in A") (3)
       func()        (4)
   return wrapper    (5)

@A                   (6)
def B(msg):          (7)
   print(msg)        (8)

为什么出错呢?
B实际是在A函数的(4)处调用的,但是呢,这里的func没有参数肯定出错了啊。
再看,A(B)返回的实际是A的内部函数wrapper。所以呢我们就得出
B=wrapper,但是这时候B(msg)=wrapper()是不成立的,所以我们给wrapper()加一个msg不就好了么。
此时代码改为

def A(func):         (1)
   def wrapper(msg): (2)
       print("in A") (3)
       func(msg)     (4) #这才是原来的B,为了符合原来参数结构
   return wrapper    (5)

@A                   (6)
def B(msg):          (7)
   print(msg)        (8)

这样我们就把装饰器改好了,但是这个装饰器有个不好的点就是,如果B有多个参数或者一些关键词参数此时装饰器就又不行了。为了通用我们把代码改成下面的

def A(func):                     (1)
   def wrapper(*args,**kwargs):  (2)
       print("in A")             (3)
       func(*args,**kwargs)      (4)
   return wrapper                (5)

@A                   (6)
def B(msg):          (7)
   print(msg)        (8)

到这里简单的装饰器基本就完事了,对函数元信息的获取啥的就不细说了。
接下来就是,带有参数的装饰器了,继续拓展我们的例子。

def A(func):                     (1)
   def wrapper(*args,**kwargs):  (2)
       print("in A")             (3)
       func(*args,**kwargs)      (4)
   return wrapper                (5)

@A(name='div')       (6)
def B(msg):          (7)
   print(msg)        (8)

到这里我只是修改了步骤(6)展示下效果,装饰器具体实现后面我们再完善。
对于带参数的装饰就等价于下面的代码

B = A(B)(name='div')

对装饰器的修改思路就是在其外层再加一层函数,为了接收参数的,修改之后如下

def A(name = 'div', *args, **kwargs):
    def _A(func):           
       def wrapper(msg, *args,**kwargs):    
           print("in A")       
           func(msg, *args, **kwargs)     
       return wrapper   
    return _A                  

@A(name='div')       
def B(msg):          
   print(msg)        

B("haha")           

对于装饰器的参数部分,习惯性的在最后加

*args, **kwargs

最后我们看下这个题的答案:

def tag(name=None,title=None,*args,**kwargs):
    def test(func):
        def test2(text,*args,**kwargs):
            content = func(text,*args,**kwargs)
            if name is None:
                # html = '<div>' + content + '</div>'
                result = f'<div>{content}</div>'
            else:
                # html = '<'+ name + ' title="' + title + '">' + content + '</' + name + '>'
                result = f'<{name} title="{title}">{content}</{name}>'
            return result
        return test2
    return test

@tag()
def render(text,*args,**kwargs):
    return text


@tag(name='p', title='text')
def render2(text,*args,**kwargs):
    return text

a = render('hello')
print(a)

b = render2('你好')
print(b)