面试题
- 用一行代码实现整数 1 至 100 之和
网上的答案是通过 range 生成 1 至 100 的整数,然后用 sum 求和:
>>> # 解法一
>>> sum(range(1, 101))
5050
这行代码确实很有美感,但你想过没有:如果是求 1 至 10000000000 之和呢? 候选人必须认识到这是一个 O(N) 算法,真的适合所有场景吗?为什么不用等差数列前 N 项和公式进行计算呢?
>>> # 解法二
>>> n = 100
>>> (n + 1) * n >> 1
5050
采用前 N 项和公式,求和时间复杂度是 O(1) ,孰优孰劣应该很明显了吧。 大家可以对比下当 N 很大时,这两种计算方式的表现:
>>> n = 100000000
>>> sum(range(1, n+1))
5000000050000000
>>> (n + 1) * n >> 1
5000000050000000
面试官喜欢引申,候选人如果只是刷题记答案而不会分析,肯定是过不了关的。
2. 如何在一个函数内部修改全局变量
在函数内部用global关键字将变量申明为全局,然后再进行修改:
>>> a = 1
>>> def func():
... global a
... a = 2
...
>>> print(a)
1
>>> func()
>>> print(a)
2
面试官还可能引申到以下概念讨论,必须滚瓜烂熟:
- 变量作用域 ( scope )
- 局部名字空间 ( locals )
- 闭包名字空间 ( globals )
- 全局名字空间 ( enclosing )
- 内建名字空间 ( builtin )
3. 列出 5 个 Python 标准库
这是一个开发性题目,面试官以考察候选人知识面以及学习深度为目的。 必须结合自身情况,选择一些自己比较熟悉的标准库作答,面试官随时可能深入讨论。
保险一点,可以回答一些常用但很浅显的,例如:
- re ,正则表达式处理
- datetime ,日期时间处理
- json , JSON 数据处理
- math , 数学计算
- random , 随机数
想要获得加分,也可以回答一些高级的,例如:
- os ,系统调用
- socket ,套接字编程与网络通讯
- threading ,多线程处理
- multiprocessing ,多进程处理
- queue ,同步任务队列
面试官很有很能深入提问,切记:如果自己不是很熟悉,就不要班门弄斧了。
4. 字典如何删除键
方法一,使用del语句进行删除,del关键字还可用于删除变量、属性
>>> ages = {'tom': 18, 'jim': 20, 'lily': 19}
>>> del ages['jim']
>>> ages
{'tom': 18, 'lily': 19}
方法二,调用pop方法进行删除,这样可以拿到被删除键对应的值:
>>> ages = {'tom': 18, 'jim': 20, 'lily': 19}
>>> jims_age = ages.pop('jim')
>>> jims_age
20
>>> ages
{'tom': 18, 'lily': 19}
5. 如何合并两个字典
>>> info1 = {'name': 'jim', 'age': 18}
>>> info2 = {'name': 'jim', 'score': 95}
方法一,调用dict对象update方法:
>>> info1.update(info2)
>>> info1
{'name': 'jim', 'age': 18, 'score': 95}
方法二:
>>> info = {**info1, **info2}
>>> info
{'name': 'jim', 'age': 18, 'score': 95}
6. 一句话解释什么样的语言能够用装饰器
函数可以作为参数传递、可以作为返回值返回的语言,都可以实现装饰器。
7. 请编写正则表达式,提取以下网页中所有 a 标签的 URL
html>
<head>
<title>编程</title>
</head>
<body>
<ul>
<li><a href="https://python.fasionchan.com">Python语言小册</a></li>
<li><a href="https://linux.fasionchan.com">学习Linux</a></li>
<li><a href="https://network.fasionchan.com">Linux网络编程</a></li>
<li><a href="https://golang.fasionchan.com">Go语言小册</a></li>
<li><a href="https://nodejs.fasionchan.com">Node.js小册</a></li>
</ul>
</body>
</html>
这题目考察标准库re模块的基本用法,难度不高,根据文本特征写正则即可:
>>> import re
>>> re.findall(r'<a.*href="([^"]+)".*>', page)
['https://python.fasionchan.com', 'https://linux.fasionchan.com', 'https://network.fasionchan.com', 'https://golang.fasionchan.com', 'https://nodejs.fasionchan.com']
注意到,参考答案中的正则表达式匹配a开标签,括号表示内容提取。 正则表达式在日常开发中应用场景很多,必须完全掌握。
8. Python 中有几个名字空间,分别是什么
Python 总共有 4 个名字空间:
- 局部名字空间 ( locals )
- 闭包名字空间 ( globals )
- 全局名字空间 ( enclosing )
- 内建名字空间 ( builtin )
9.字典推导式使用方法?字典推导式如何格式化 cookie 值?
字典推导式
字典推导式(dict comprehensions)和列表推导的使用方法也是类似的。
字典解析是使用大括号包围,并且需要两个表达式,一个生成key, 一个生成value 两个表达式之间使用冒号分割,返回结果是字典.
![aff4aa5e811a18874ae2128c13f1909a.png](https://img-blog.csdnimg.cn/img_convert/aff4aa5e811a18874ae2128c13f1909a.png)
cookie:
SESSID=et4a33og7nbftv60j3v9m86cro; Hm_lvt_51e3cc975b346e7705d8c255164036b3=1561553685; Hm_lpvt_51e3cc975b346e7705d8c255164036b3=1561553685
- 首先分析一下浏览器中cookie的结构
- 基本上是:key=value; key=value; key=value
- 其中key=value之间用一个分号和一个空格分开
首先写一下不用字典推导式,把cookie转化为字典的代码:
def cookie_to_dic(cookie):
cookie_dic = {}
for i in cookie.split('; '):
cookie_dic[i.split('=')[0]] = i.split('=')[1]
return cookie_dic
然后用字典推导式的代码:
def cookie_to_dic(cookie):
return {item.split('=')[0]: item.split('=')[1] for item in cookie.split('; ')}
10. 类 class 和元类 metaclass 的有什么区别?
首先在python中,所有东西都是对象。当python在执行带class语句的时候,会初始化一个类对象放在内存里面。这个对象(类)自身拥有创建对象(通常我们说的实例,但是在python中还是对象)的能力。
class Student(object):
pass
print type('123')
print type(123)
print type(Student())
结果:
<type 'str'>
<type 'int'>
<class '__main__.Student'>
type(类名,父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
MetaClass元类,本质也是一个类,但和普通类的用法不同,它可以对类内部的定义(包括类属性和类方法)进行动态的修改。可以这么说,使用元类的主要目的就是为了实现在创建类时,能够动态地改变类中定义的属性或者方法。
11.什么是单例模式?单例模式的作用?
单例模式(Singleton Pattern)是 编程语言 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。是指:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
使用场景: 1、要求生产唯一序列号。 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
12.Python 中内存泄漏有哪几种?
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。导致程序运行速度减慢甚至系统崩溃等严重后果。
- 有 __del__() 函数的对象间的循环引用是导致内存泄漏的主凶。
2. 扩展库内存泄露
3. 一种是全局容器里的对象没有删除
13.简单描述一下 asyncio 模块实现异步的原理?
asyncio是做什么的?
- 异步网络操作
- 并发
- 协程
===>> python3.0时代,标准库里的异步网络模块:select(非常底层)
===>> python3.0时代,第三方异步网络库:Tornado
===>> python3.4时代,asyncio:支持TCP,子进程.直接内置了对异步IO的支持。
现在的asyncio,有了很多的模块已经在支持:aiohttp,aiodns,aioredis等等.asyncio是python3.4版本引入到标准库.
它使用一种单线程单进程的的方式实现并发,应用的各个部分彼此合作, 可以显示的切换任务,一般会在程序阻塞I/O操作的时候发生上下文切换如等待读写文件,或者请求网络。同时asyncio也支持调度代码在将来的某个特定事件运行,从而支持一个协程等待另一个协程完成,以处理系统信号和识别其他一些事件。
14.守护线程和非守护线程是什么?
所谓守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因 此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。
在创建新线程时,子线程会从其父线程继承其线程属性,主线程是普通的非守护线程,默认情况下,它所创建的任何线程都是非守护线程。