python170道面试题上

语言特性
1. 谈谈对 Python 和其他语言的区别
2. 简述解释型和编译型编程语言
3. Python 的解释器种类以及相关特点?
4. Python3 和 Python2 的区别?
5. Python3 和 Python2 中 int 和 long 区别?
6. xrange 和 range 的区别?
编码规范
7. 什么是 PEP8?
8. 了解 Python 之禅么?
9. 了解 DocStrings 么?
10. 了解类型注解么?
11. 例举你知道 Python 对象的命名规范,例如方法或者类等
12. Python 中的注释有几种?
13. 如何优雅的给一个函数加注释?
14. 如何给变量加注释?
15. Python 代码缩进中是否支持 Tab 键和空格混用。
16. 是否可以在一句 import 中导入多个库?
17. 在给 Py 文件命名的时候需要注意什么?
18. 例举几个规范 Python 代码风格的工具
数据类型-字符串
19. 列举 Python 中的基本数据类型?
20. 如何区别可变数据类型和不可变数据类型
21. 将"hello world"转换为首字母大写"Hello World"
22. 如何检测字符串中只含有数字?
23. 将字符串"ilovechina"进行反转
24. Python 中的字符串格式化方式你知道哪些?
25. 有一个字符串开头和末尾都有空格,比如“ adabdw ”,要求写一个函数把这个字符串的前后空格都去掉。
26. 获取字符串”123456“最后的两个字符。
27. 一个编码为 GBK 的字符串 S,要将其转成 UTF-8 编码的字符串,应如何操作?
28. (1)s="info:xiaoZhang 33 shandong",用正则切分字符串输出['info', 'xiaoZhang', '33', 'shandong']。(2)a = "你好 中国 ",去除多余空格只留一个空格。
29. (1) 怎样将字符串转换为小写。 (2) 单引号、双引号、三引号的区别?
数据类型 - 列表
30. 已知 AList = [1,2,3,1,2],对 AList 列表元素去重,写出具体过程。
31. 如何实现 "1,2,3" 变成 ["1","2","3"]
32. 给定两个 list,A 和 B,找出相同元素和不同元素
33. [[1,2],[3,4],[5,6]] 一行代码展开该列表,得出 [1,2,3,4,5,6]
34. 合并列表 [1,5,7,9] 和 [2,2,6,8]
35. 如何打乱一个列表的元素?
数据类型 - 字典
36. 字典操作中 del 和 pop 有什么区别
37. 按照字典的内的年龄排序
38. 请合并下面两个字典 a = {"A":1,"B":2},b = {"C":3,"D":4}
39. 如何使用生成式的方式生成一个字典,写一段功能代码。
40. 如何把元组 ("a","b") 和元组 (1,2),变为字典 {"a":1,"b":2}
数据类型 - 综合
41. 下列字典对象键类型不正确的是?
42. 如何交换字典 {"A":1,"B":2}的键和值
43. Python 里面如何实现 tuple 和 list 的转换?
44. 我们知道对于列表可以使用切片操作进行部分元素的选择,那么如何对生成器类型的对象实现相同的功能呢?
45. 请将 [i for i in range(3)] 改成生成器
46. a="hello" 和 b="你好" 编码成 bytes 类型
47. 下面的代码输出结果是什么?
48. 下面的代码输出的结果是什么?
操作类题目
49. Python 交换两个变量的值
50. 在读文件操作的时候会使用 read、readline 或者 readlines,简述它们各自的作用
51. json 序列化时,可以处理的数据类型有哪些?如何定制支持 datetime 类型?
52. json 序列化时,默认遇到中文会转换成 unicode,如果想要保留中文怎么办?
53. 有两个磁盘文件 A 和 B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件 C 中。
54. 如果当前的日期为 20190530,要求写一个函数输出 N 天后的日期,(比如 N 为 2,则输出 20190601)。
55. 写一个函数,接收整数参数 n,返回一个函数,函数的功能是把函数的参数和 n 相乘并把结果返回。
56. 下面代码会存在什么问题,如何改进?
57. 一行代码输出 1-100 之间的所有偶数。
58. with 语句的作用,写一段代码?
59. Python 字典和 json 字符串相互转化方法
60. 请写一个 Python 逻辑,计算一个文件中的大写字母数量
61. 请写一段 Python连接Mongo数据库,然后的查询代码。
62.说一说Redis的基本类型
63. 请写一段 Python连接Redis数据库的代码。
64. 请写一段 Python连接Mysql数据库的代码。
65.了解Redis的事务么
66.了解数据库的三范式么?
67.了解分布式锁么
68.用 Python 实现一个 Reids 的分布式锁的功能
69.写一段 Python 使用 mongo 数据库创建索引的代码:
高级特性
70. 函数装饰器有什么作用?请列举说明?
71. Python 垃圾回收机制?
72. 魔法函数 _call_怎么使用?
73. 如何判断一个对象是函数还是方法?
74. @classmethod 和 @staticmethod 用法和区别
75. Python 中的接口如何实现?
76. Python 中的反射了解么?
77. metaclass 作用?以及应用场景?
78. hasattr()、getattr()、setattr() 的用法
79. 请列举你知道的 Python 的魔法方法及用途。
80. 如何知道一个 Python 对象的类型?
81. Python 的传参是传值还是传址?
82. Python 中的元类 (metaclass) 使用举例
83. 简述 any() 和 all() 方法
84. filter 方法求出列表所有奇数并构造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
85. 什么是猴子补丁?
86. 在 Python 中是如何管理内存的?
87. 当退出 Python 时是否释放所有内存分配?
正则表达式
88. (1)使用正则表达式匹配出www.baidu.com中的地址(2)a="张明 98 分",用 re.sub,将 98 替换为 100
89. 正则表达式匹配中(.*)和(.*?)匹配区别?
90. 写一段匹配邮箱的正则表达式
其他内容
91. 解释一下 Python 中 pass 语句的作用?
92. 简述你对 input()函数的理解
93. Python 中的 is 和==
94. Python 中的作用域
95. 三元运算写法和应用场景?
96. 了解 enumerate 么?
97. 列举 5 个 Python 中的标准模块
98. 如何在函数中设置一个全局变量
99. pathlib 的用法举例
100. Python 中的异常处理,写一个简单的应用场景
101. Python 中递归的最大次数,那如何突破呢?
102. 什么是面向对象的 mro
103. isinstance 作用以及应用场景?
104. 什么是断言?应用场景?
105. lambda 表达式格式以及应用场景?
106. 新式类和旧式类的区别
107. dir()是干什么用的?
108. 一个包里有三个模块,demo1.py、demo2.py、demo3.py,但使用 from tools import *导入模块时,如何保证只有 demo1、demo3 被导入了。
109. 列举 5 个 Python 中的异常类型以及其含义
110. copy 和 deepcopy 的区别是什么?
111. 代码中经常遇到的*args, **kwargs 含义及用法。
112. Python 中会有函数或成员变量包含单下划线前缀和结尾,和双下划线前缀结尾,区别是什么?
113. w、a+、wb 文件写入模式的区别
114. 举例 sort 和 sorted 的区别
115. 什么是负索引?
116. pprint 模块是干什么的?
117. 解释一下 Python 中的赋值运算符
118. 解释一下 Python 中的逻辑运算符
119. 讲讲 Python 中的位运算符
120. 在 Python 中如何使用多进制数字?
121. 怎样声明多个变量并赋值?
算法和数据结构
122. 已知:
123. 用 Python 实现一个二分查找的函数
124. Python 单例模式的实现方法
125. 使用 Python 实现一个斐波那契数列
126. 找出列表中的重复数字
127. 找出列表中的单个数字
128. 写一个冒泡排序
129. 写一个快速排序
130. 写一个拓扑排序
131. Python 实现一个二进制计算
132. 有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法。
133. 单链表反转
134. 交叉链表求交点
135. 用队列实现栈
136. 找出数据流的中位数
137. 二叉搜索树中第 K 小的元素
爬虫相关
138. 在 requests 模块中,requests.content 和 requests.text 什么区别
139. 简要写一下 lxml 模块的使用方法框架
140. 说一说 scrapy 的工作流程
141. scrapy 的去重原理
142. scrapy 中间件有几种类,你用过哪些中间件
143. 你写爬虫的时候都遇到过什么?反爬虫措施,你是怎么解决的?
144. 为什么会用到代理?
145. 代理失效了怎么处理?
146. 列出你知道 header 的内容以及信息
147. 说一说打开浏览器访问 www.baidu.com 获取到结果,整个流程。
148. 爬取速度过快出现了验证码怎么处理
149. scrapy 和 scrapy-redis 有什么区别?为什么选择 redis 数据库?
150. 分布式爬虫主要解决什么问题
151. 写爬虫是用多进程好?还是多线程好? 为什么?
152. 解析网页的解析器使用最多的是哪几个
153. 需要登录的网页,如何解决同时限制 ip,cookie,session(其中有一些是动态生成的)在不使用动态爬取的情况下?
154. 验证码的解决?
155. 使用最多的数据库(mysql,mongodb,redis 等),对他的理解?
网络编程
156. TCP 和 UDP 的区别?
157. 简要介绍三次握手和四次挥手
158. 什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?
并发
159. 举例说明 concurrent.future 的中线程池的用法
160. 说一说多线程,多进程和协程的区别。
161. 简述 GIL
162. 进程之间如何通信
163. IO 多路复用的作用?
164. select、poll、epoll 模型的区别?
165. 什么是并发和并行?
166. 一个线程 1 让线程 2 去调用一个函数怎么实现
167. 解释什么是异步非阻塞?
168. threading.local 的作用?
Git 面试题
169. 说说你知道的 git 命令
170. git 如何查看某次提交修改的内容
语言特性
 
1. 谈谈对 Python 和其他语言的区别
 
答:Python 是一门语法简洁优美,功能强大无比,应用领域非常广泛,具有强大完备的第三方库,他是一门强类型的可移植、可扩展,可嵌入的解释型编程语言,属于动态语言。
 
拿 C 语言和 Python 比: Python 的第三方类库比较齐全并且使用简洁,很少代码就能实现一些功能,如果用 C 去实现相同的功能可能就比较复杂。但是对于速度来说 Python 的运行速度相较于 C 就比较慢了。所以有利的同时也有弊端,毕竟我们的学习成本降低了。
 
2. 简述解释型和编译型编程语言
 
答:解释型语言是在运行程序的时候才翻译,每执行一次,要翻译一次,效率较低。 编译型就是直接编译成机型可以执行的,只翻译一次,所以效率相对来说较高。
 
3. Python 的解释器种类以及相关特点?
 
答:
 
CPython c 语言开发的,使用最广的解释器
IPython 基于 cPython 之上的一个交互式计时器,交互方式增强功能和 cPython 一样
PyPy 目标是执行效率,采用 JIT 技术。对 Python 代码进行动态编译,提高执行效率
JPython 运行在 Java 上的解释器,直接把 Python 代码编译成 Java 字节码执行
IronPython 运行在微软 .NET 平台上的解释器,把 Python 编译成 . NET 的字节码。
4. Python3 和 Python2 的区别?
 
答: 这里例举 5 条
 
print 在 Python3 中是函数必须加括号,Python2 中 print 为 class。
Python2 中使用 xrange,Python3 使用 range。
Python2 中默认的字符串类型默认是 ASCII,Python3 中默认的字符串类型是 Unicode。
Python2 中/的结果是整型,Python3 中是浮点类型。
Python2 中声明元类:_metaclass_ = MetaClass,Python3 中声明元类:class newclass(metaclass=MetaClass):pass。
5. Python3 和 Python2 中 int 和 long 区别?
 
答:Python2 有 int 和 long 类型。int 类型最大值不能超过 sys.maxint,而且这个最大值是平台相关的。可以通过在数字的末尾附上一个L来定义长整型,显然,它比 int 类型表示的数字范围更大。在 Python3 里,只有一种整数类型 int,大多数情况下,和 Python2中的长整型类似。
 
6. xrange 和 range 的区别?
 
答:xrange 是在 Python2 中的用法,Python3 中只有 range xrange 用法与 range 完全相同,所不同的是生成的不是一个 list 对象,而是一个生成器。
 
编码规范
 
7. 什么是 PEP8?
 
答:PEP8 通常会听别人提到,但是具体的指什么内容呢,简单介绍下。 《Python Enhancement Proposal #8》(8 号 Python 增强提案)又叫 PEP8,他针对的 Python 代码格式而编订的风格指南。
 
8. 了解 Python 之禅么?
 
答:通过 import this 语句可以获取其具体的内容。它告诉大家如何写出高效整洁的代码。
 
9. 了解 DocStrings 么?
 
答:DocStrings 文档字符串是一个重要工具,用于解释文档程序,帮助你的程序文档更加简单易懂。主要是解释代码作用的。
 
10. 了解类型注解么?
 
答:PEP 484 引入了类型提示,这使得可以对 Python 代码进行静态类型检查。 在使用 Ide 的时候可以获取到参数的类型,更方便传入参数。使用格式如下
 
def foo(num: int) -> None:
    print(f"接收到的数字是:{num}")
介绍下这个简单例子,我们可以在函数的参数部分使用参数名+:+类型,来指定参数可以接受的类型,这里的话就是 num 参数为 int 类型,然后后面->接的是返回值的类型。这里返回值为 None,然后通过 fstring 格式化字符串输出传入的数字。
 
11. 例举你知道 Python 对象的命名规范,例如方法或者类等
 
答:
 
类:总是使用首字母大写单词串,如 MyClass。内部类可以使用额外的前导下划线。 变量:小写,由下划线连接各个单词。方法名类似 常量:常量名所有字母大写 等
 
12. Python 中的注释有几种?
 
答:总体来说分为两种,单行注释和多行注释。
 
单行注释在行首是 #。
多行注释可以使用三个单引号或三个双引号,包括要注释的内容。
13. 如何优雅的给一个函数加注释?
 
答:可以使用 docstring 配合类型注解
 
14. 如何给变量加注释?
 
答:可以通过变量名:类型的方式如下
 
a: str = "this is string type"
15. Python 代码缩进中是否支持 Tab 键和空格混用。
 
答:不允许 tab 键和空格键混用,这种现象在使用 sublime 的时候尤为明显。
 
一般推荐使用 4 个空格替代 tab 键。
 
16. 是否可以在一句 import 中导入多个库?
 
答:可以是可以,但是不推荐。因为一次导入多个模块可读性不是很好,所以一行导入一个模块会比较好。同样的尽量少用 from modulename import *,因为判断某个函数或者属性的来源有些困难,不方便调试,可读性也降低了。
 
17. 在给 Py 文件命名的时候需要注意什么?
 
答:给文件命名的时候不要和标准库库的一些模块重复,比如 abc。 另外要名字要有意义,不建议数字开头或者中文命名。
 
18. 例举几个规范 Python 代码风格的工具
 
答:pylint 和 flake8
 
数据类型-字符串
 
19. 列举 Python 中的基本数据类型?
 
答: Python3 中有六个标准的数据类型:字符串(String)、数字(Digit)、列表(List)、元组(Tuple)、集合(Sets)、字典(Dictionary)。
 
20. 如何区别可变数据类型和不可变数据类型
 
答: 从对象内存地址方向来说
 
可变数据类型:在内存地址不变的情况下,值可改变(列表和字典是可变类型,但是字典中的 key 值必须是不可变类型)
不可变数据类型:内存改变,值也跟着改变。(数字,字符串,布尔类型,都是不可变类型)可以通过 id() 方法进行内存地址的检测。
21. 将"hello world"转换为首字母大写"Hello World"
 
答: 这个得看清题目是要求两个单词首字母都要大写,如果只是第一个单词首字母大小的话,只使用 capitalize 即可,但是这里是两个单词,所以用下面的方法。
 
arr = "hello world".split(" ")
new_str = f"{arr[0].capitalize()} {arr[1].capitalize()}"
print(new_str)
后来评论中有朋友提到了下面的方法,这里感谢这位朋友提醒。方案如下
 
"hello world".title()
非常简单一句话搞定。
 
22. 如何检测字符串中只含有数字?
 
答:可以通过 isdigit 方法,例子如下
 
s1 = "12223".isdigit()
print(s1)
 
s2 = "12223a".isdigit()
print(s2)
 
#结果如下:
#True
#False
23. 将字符串"ilovechina"进行反转
 
答:
 
s1 = "ilovechina"[::-1]
print(s1)
24. Python 中的字符串格式化方式你知道哪些?
 
答:%s,format,fstring(Python3.6 开始才支持,现在推荐的写法)
 
25. 有一个字符串开头和末尾都有空格,比如“ adabdw ”,要求写一个函数把这个字符串的前后空格都去掉。
 
答:因为题目要是写一个函数所以我们不能直接使用 strip,不过我们可以把它封装到函数啊
 
def strip_function(s1):
    return s1.strip()
 
s1 = " adabdw "
print(strip_function(s1))
26. 获取字符串”123456“最后的两个字符。
 
答:切片使用的考察,最后两个即开始索引是 -2,代码如下
 
a = "123456"
print(a[-2::])
27. 一个编码为 GBK 的字符串 S,要将其转成 UTF-8 编码的字符串,应如何操作?
 
答:
 
a= "S".encode("gbk").decode("utf-8",'ignore')
print(a)
28. (1)s="info:xiaoZhang 33 shandong",用正则切分字符串输出['info', 'xiaoZhang', '33', 'shandong']。(2)a = "你好 中国 ",去除多余空格只留一个空格。
 
答:
 
(1)我们需要根据冒号或者空格切分
 
import re
 
s = "info:xiaoZhang 33 shandong"
res = re.split(r":| ", s)
print(res)
(2)
 
s = "你好     中国  "
print(" ".join(s.split()))
29. (1) 怎样将字符串转换为小写。 (2) 单引号、双引号、三引号的区别?
 
答: (1) 使用字符串的 lower() 方法。
 
(2)单独使用单引号和双引号没什么区别,但是如果引号里面还需要使用引号的时候,就需要这两个配合使用了,然后说三引号,同样的三引号也分为三单引号和三双引号,两个都可以声名长的字符串时候使用,如果使用 docstring 就需要使用三双引号。
 
数据类型 - 列表
 
30. 已知 AList = [1,2,3,1,2],对 AList 列表元素去重,写出具体过程。
 
答:
 
list(set(AList))
31. 如何实现 "1,2,3" 变成 ["1","2","3"]
 
答:
 
s = "1,2,3"
print(s.split(","))
32. 给定两个 list,A 和 B,找出相同元素和不同元素
 
答:
 
A、B 中相同元素:print(set(A)&set(B)) 
A、B 中不同元素:print(set(A)^set(B))
33. [[1,2],[3,4],[5,6]] 一行代码展开该列表,得出 [1,2,3,4,5,6]
 
答:
 
l = [[1,2],[3,4],[5,6]]
x=[j for i in l for j in i]  
print(x)
34. 合并列表 [1,5,7,9] 和 [2,2,6,8]
 
答:使用 extend 和 + 都可以。
 
a = [1,5,7,9]
b = [2,2,6,8]
a.extend(b)
print(a)
35. 如何打乱一个列表的元素?
 
答:
 
import random
 
a = [1, 2, 3, 4, 5]
random.shuffle(a)
print(a)
数据类型 - 字典
 
36. 字典操作中 del 和 pop 有什么区别
 
答:del 可以根据索引(元素所在位置)来删除的,没有返回值。 pop 可以根据索引弹出一个值,然后可以接收它的返回值。
 
37. 按照字典的内的年龄排序
 
d1 = [
    {'name':'alice', 'age':38},
    {'name':'bob', 'age':18},
    {'name':'Carl', 'age':28},
]
答:
 
d1 = [
    {'name': 'alice', 'age': 38},
    {'name': 'bob', 'age': 18},
    {'name': 'Carl', 'age': 28},
]
 
print(sorted(d1, key=lambda x:x["age"]))
38. 请合并下面两个字典 a = {"A":1,"B":2},b = {"C":3,"D":4}
 
答: 合并字典方法很多,可以使用 a.update(b) 或者下面字典解包的方式
 
a = {"A":1,"B":2}
b = {"C":3,"D":4}
print({**a,**b})
39. 如何使用生成式的方式生成一个字典,写一段功能代码。
 
答:
 
# 需求 3: 把字典的 key 和 value 值调换;
d = {'a':'1', 'b':'2'}
 
print({v:k for k,v in d.items()})
40. 如何把元组 ("a","b") 和元组 (1,2),变为字典 {"a":1,"b":2}
 
答 zip 的使用,但是最后记得把 zip 对象再转换为字典。
 
a = ("a", "b")
b = (1, 2)
print(dict(zip(a, b)))
数据类型 - 综合
 
41. 下列字典对象键类型不正确的是?
 
A:{1:0,2:0,3:0}
B:{"a":0, "b":0, "c":0}
C: {(1,2):0, (2,3):0}
D: {[1,2]:0, [2,3]:0}
答:D 因为只有可 hash 的对象才能做字典的键,列表是可变类型不是可 hash 对象,所以不能用列表做为字典的键。
 
42. 如何交换字典 {"A":1,"B":2}的键和值
 
答:
 
s =  {"A":1,"B":2}
 
#方法一:
dict_new = {value:key for key,value in s.items()}
 
# 方法二:
new_s= dict(zip(s.values(),s.keys()))
43. Python 里面如何实现 tuple 和 list 的转换?
 
答: Python 中的类型转换,一般通过类型强转即可完成 tuple 转 list 是 list() 方法 list 转 tuple 使用 tuple() 方法
 
44. 我们知道对于列表可以使用切片操作进行部分元素的选择,那么如何对生成器类型的对象实现相同的功能呢?
 
答: 这个题目考察了 Python 标准库的 itertools 模快的掌握情况,该模块提供了操作生成器的一些方法。 对于生成器类型我们使用 islice 方法来实现切片的功能。例子如下
 
from itertools import islice
gen = iter(range(10)) #iter()函数用来生成迭代器
#第一个参数是迭代器,第二个参数起始索引,第三个参数结束索引,不支持负数索引
for i in islice(gen,0,4): 
    print(i)
45. 请将 [i for i in range(3)] 改成生成器
 
答:通过把列表生产式的中括号,改为小括号我们就实现了生产器的功能即,
 
(i for i in range(3))
46. a="hello" 和 b="你好" 编码成 bytes 类型
 
答: 这个题目一共三种方式,第一种是在字符串的前面加一个 b,第二种可以使用 bytes 方法,第三种使用字符串 encode 方法。具体代码如下,abc 代表三种情况
 
a = b"hello"
b = bytes("你好", "utf-8")
c = "你好".encode("utf-8")
print(a, b, c)
47. 下面的代码输出结果是什么?
 
a = (1,2,3,[4,5,6,7],8)
a[2] = 2
答: 我们知道元组里的元素是不能改变的所以这个题目的答案是出现异常。
 
48. 下面的代码输出的结果是什么?
 
a = (1,2,3,[4,5,6,7],8)
a[3][0] = 2
答:前面我说了元组的里元素是不能改变的,这句话严格来说是不准确的,如果元组里面元素本身就是可变类型,比如列表,那么在操作这个元素里的对象时,其内存地址也是不变的。a[3] 对应的元素是列表,然后对列表第一个元素赋值,所以最后的结果是: (1,2,3,[2,5,6,7],8)
 
操作类题目
 
49. Python 交换两个变量的值
 
答:在 Python 中交换两个对象的值通过下面的方式即可
 
a , b = b ,a 
但是需要强调的是这并不是元组解包,通过 dis 模块可以发现,这是交换操作的字节码是 ROT_TWO,意思是在栈的顶端做两个值的互换操作。
 
50. 在读文件操作的时候会使用 read、readline 或者 readlines,简述它们各自的作用
 
答:.read() 每次读取整个文件,它通常用于将文件内容放到一个字符串变量中。如果希望一行一行的输出那么就可以使用 readline(),该方法会把文件的内容加载到内存,所以对于对于大文件的读取操作来说非常的消耗内存资源,此时就可以通过 readlines 方法,将文件的句柄生成一个生产器,然后去读就可以了。
 
51. json 序列化时,可以处理的数据类型有哪些?如何定制支持 datetime 类型?
 
答: 可以处理的数据类型是 str、int、list、tuple、dict、bool、None, 因为 datetime 类不支持 json 序列化,所以我们对它进行拓展。
 
# 自定义时间序列化
import json
from datetime import datetime, date
 
# JSONEncoder 不知道怎么去把这个数据转换成 json 字符串的时候
# ,它就会去调 default()函数,所以都是重写这个函数来处理它本身不支持的数据类型,
# default()函数默#认是直接抛异常的。
class DateToJson(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(obj, date):
            return obj.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, obj)
 
 
d = {'name': 'cxa', 'data': datetime.now()}
print(json.dumps(d, cls=DateToJson))
52. json 序列化时,默认遇到中文会转换成 unicode,如果想要保留中文怎么办?
 
答:可以通过 json.dumps 的 ensure_ascii 参数解决,代码示例如下:
 
import json
a=json.dumps({"name":"张三"},ensure_ascii=False)
print(a)
53. 有两个磁盘文件 A 和 B,各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件 C 中。
 
答:
 
#文件 A.txt 内容为 ASDCF
#文件 B.txt 内容为 EFGGTG
with open("A.txt") as f1:
    f1_txt = f1.readline()
with open("B.txt") as f2:
    f2_txt = f2.readline()
f3_txt = f1_txt + f2_txt
 
f3_list = sorted(f3_txt)
 
with open("C.txt", "a+") as f:
     f.write("".join(f3_list))
输出的文件 C 的内容为 ACDEFFGGGST
 
54. 如果当前的日期为 20190530,要求写一个函数输出 N 天后的日期,(比如 N 为 2,则输出 20190601)。
 
答:这个题目考察的是 datetime 里的 timedelta 方法的使用,参数可选、默认值都为 0:datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0) 通过这个参数可以指定不同的日期类型进行加减操作,这里我们需要改的是 days,代码如下
 
import datetime
 
 
def datetime_operate(n: int):
    now = datetime.datetime.now()  # 获取当前时间
    _new_date = now + datetime.timedelta(days=n)  # 获取指定天数后的新日期
    new_date = _new_date.strftime("%Y%m%d")  # 转换为指定的输出格式
    return new_date
 
 
if __name__ == '__main__':
    print(datetime_operate(4))
55. 写一个函数,接收整数参数 n,返回一个函数,函数的功能是把函数的参数和 n 相乘并把结果返回。
 
答:这个题目考查了闭包的使用代码示例如下,返回函数之类型是函数对象。
 
def mul_operate(num):
    def g(val):
        return num * val
 
    return g
 
 
m = mul_operate(8)
print(m(5))
56. 下面代码会存在什么问题,如何改进?
 
def strappend(num):
    str='first'
    for i in range(num):
        str+=str(i)
    return str
答: 首先不应该使用 Python 的内置类似 str 作为变量名这里我把它改为了 s,另外在Python,str 是个不可变对象,每次迭代都会生成新的存储空间,num 越大,创建的 str 对象就会越多,内存消耗越大。使用 yield 改成生成器即可, 还有一点就是命名规范的位置,函数名改为_分割比较好,完整的代码如下:
 
def str_append(num):
    s = 'first'
    for i in range(num):
        s += str(i)
        yield s
 
if __name__ == '__main__':
    for i in str_append(3):
        print(i)
57. 一行代码输出 1-100 之间的所有偶数。
 
答:可以通过列表生成式,然后使用与操作如果如 1 与之后结果为 0 则表明为偶数,等于 1 则为奇数。
 
# 方法1
print([i for i in range(1, 101) if i & 0x1 == 0])
# 方法2:测试发现方法二效率更高
print(list(range(2, 101, 2)))
58. with 语句的作用,写一段代码?
 
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
 
其他的内容看下面我之前写的代码。
 
#一般访问文件资源时我们会这样处理:
 
f = open(
    'c:\test.txt', 'r')
data = f.read()
f.close()
# 这样写没有错,但是容易犯两个毛病:
# 1. 如果在读写时出现异常而忘了异常处理。
# 2. 忘了关闭文件句柄
 
#以下的加强版本的写法:
 
f = open('c:\test.txt', 'r')
try:
    data = f.read()
finally:
    f.close()
 
#以上的写法就可以避免因读取文件时异常的发生而没有关闭问题的处理了。代码长了一些。
#但使用 with 有更优雅的写法:
 
with open(r'c:\test.txt', 'r') as f:
    data = f.read()
#with 的实现
 
class Test:
    def __enter__(self):
        print('__enter__() is call!')
        return self
 
    def dosomething(self):
        print('dosomethong!')
 
    def __exit__(self, exc_type, exc_value, traceback):
        print('__exit__() is call!')
        print(f'type:{exc_type}')
        print(f'value:{exc_value}')
        print(f'trace:{traceback}')
        print('__exit()__ is call!')
 
with Test() as sample:
      pass
 
#当对象被实例化时,就会主动调用__enter__()方法,任务执行完成后就会调用__exit__()方法,
#另外,注意到,__exit__()方法是带有三个参数的(exc_type, exc_value, traceback),
#依据上面的官方说明:如果上下文运行时没有异常发生,那么三个参数都将置为 None, 
#这里三个参数由于没有发生异常,的确是置为了 None, 与预期一致.
 
# 修改后不出异常了
class Test:
    def __enter__(self):
        print('__enter__() is call!')
        return self
 
    def dosomething(self):
        x = 1/0
        print('dosomethong!')
 
    def __exit__(self, exc_type, exc_value, traceback):
        print('__exit__() is call!')
        print(f'type:{exc_type}')
        print(f'value:{exc_value}')
        print(f'trace:{traceback}')
        print('__exit()__ is call!')
        return True
 
 
with Test() as sample:
59. Python 字典和 json 字符串相互转化方法
 
答:
 
在 Python 中使用 dumps 方法 将 dict 对象转为 Json 对象,使用 loads 方法可以将 Json 对象转为 dict 对象。
 
dic = {'a': 123, 'b': "456", 'c': "liming"}
json_str = json.dumps(dic)
dic2 = json.loads(json_str)
print(dic2)
打印:
'{"a": 123, "b": "456", "c": "liming"}'
{'a': 123, 'b': '456', 'c': 'liming'}
我们再来看一个特殊的例子
 
import json
dic = {'a': 123, 'b': "456", 'c': "liming"}
dic_str = json.loads(str(dic).replace("'", "\""))
print(dic_str)
下面我解释下上面代码是测试什么:
 
首先 json.loads(jsonstr) 这里面的参数只能是 jsonstr 格式的字符串.
当我们使用 str 将字典 dic 转化为字符串以后,得到的结果为:"{'a': 123, 'b': '456', 'c': 'liming'}"。
如果直接使用 json.loads(str(dic)) 你会发现出现错误,原因就是,单引号的字符串不符合Json的标准格式所以再次使用了 replace("'", "\"")。得到字典
其实这个例子主要目的是告诉大家 Json 的标准格式是不支持单引号型字符串的,否则会出现以下错误。
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
60. 请写一个 Python 逻辑,计算一个文件中的大写字母数量
 
答:
 
with open('A.txt') as fs:
    count = 0
    for i in fs.read():
        if i.isupper():
            count += 1
print(count)
61. 请写一段 Python连接Mongo数据库,然后的查询代码。
 
答:
 
# -*- coding: utf-8 -*-
# @Author : 陈祥安
import pymongo
db_configs = {
    'type': 'mongo',
    'host': '地址',
    'port': '端口',
    'user': 'spider_data',
    'passwd': '密码',
    'db_name': 'spider_data'
}
 
 
class Mongo():
    def __init__(self, db=db_configs["db_name"], username=db_configs["user"],
                 password=db_configs["passwd"]):
        self.client = pymongo.MongoClient(f'mongodb://{db_configs["host"]}:db_configs["port"]')
        self.username = username
        self.password = password
        if self.username and self.password:
            self.db1 = self.client[db].authenticate(self.username, self.password)
        self.db1 = self.client[db]
 
    def find_data(self):
        # 获取状态为0的数据
        data = self.db1.test.find({"status": 0})
        gen = (item for item in data)
        return gen
 
if __name__ == '__main__':
    m = Mongo()
    print(m.find_data())
62.说一说Redis的基本类型
 
答: Redis 支持五种数据类型: string(字符串) 、 hash(哈希)、list(列表) 、 set(集合) 及 zset(sorted set: 有序集合)。
 
63. 请写一段 Python连接Redis数据库的代码。
 
答:
 
from redis import StrictRedis, ConnectionPool
redis_url="redis://:xxxx@112.27.10.168:6379/15"
pool = ConnectionPool.from_url(redis_url, decode_responses=True)
r= StrictRedis(connection_pool=pool)
64. 请写一段 Python连接Mysql数据库的代码。
 
答:
 
conn = pymysql.connect(host='localhost', 
port=3306, user='root', 
passwd='1234', db='user', charset='utf8mb4')#声明mysql连接对象
cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)#查询结果以字典的形式
cursor.execute(sql语句字符串)#执行sql语句
conn.close()#关闭链接
65.了解Redis的事务么
 
答: 简单理解,可以认为 redis 事务是一些列 redis 命令的集合,并且有如下两个特点: 1.事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 2.事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。 一般来说,事务有四个性质称为ACID,分别是原子性,一致性,隔离性和持久性。 一个事务从开始到执行会经历以下三个阶段:
 
开始事务
命令入队
执行事务 代码示例:
import redis
import sys
def run():   
    try:
        conn=redis.StrictRedis('192.168.80.41')
       # Python中redis事务是通过pipeline的封装实现的
        pipe=conn.pipeline()
        pipe.sadd('s001','a')
        sys.exit()
        #在事务还没有提交前退出,所以事务不会被执行。
        pipe.sadd('s001','b')
        pipe.execute()
        pass
    except Exception as err:
        print(err)
        pass
if __name__=="__main__":
      run()
66.了解数据库的三范式么?
 
答: 经过研究和对使用中问题的总结,对于设计数据库提出了一些规范,这些规范被称为范式 一般需要遵守下面3范式即可: 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。 第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
 
67.了解分布式锁么
 
答: 分布式锁是控制分布式系统之间的同步访问共享资源的一种方式。 对于分布式锁的目标,我们必须首先明确三点:
 
任何一个时间点必须只能够有一个客户端拥有锁。
不能够有死锁,也就是最终客户端都能够获得锁,尽管可能会经历失败。
错误容忍性要好,只要有大部分的Redis实例存活,客户端就应该能够获得锁。 分布式锁的条件 互斥性:分布式锁需要保证在不同节点的不同线程的互斥 可重入性:同一个节点上的同一个线程如果获取了锁之后,能够再次获取这个锁。 锁超时:支持超时释放锁,防止死锁 高效,高可用:加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级。 支持阻塞和非阻塞:可以实现超时获取失败,tryLock(long timeOut) 支持公平锁和非公平锁
分布式锁的实现方案 1、数据库实现(乐观锁) 2、基于zookeeper的实现 3、基于Redis的实现(推荐)
 
68.用 Python 实现一个 Reids 的分布式锁的功能
 
答:REDIS分布式锁实现的方式:SETNX + GETSET,NX是Not eXists的缩写,如SETNX命令就应该理解为:SET if Not eXists。 多个进程执行以下Redis命令:
 
SETNX lock.foo <current Unix time + lock timeout + 1>
如果 SETNX 返回1,说明该进程获得锁,SETNX将键 lock.foo 的值设置为锁的超时时间(当前时间 + 锁的有效时间)。 如果 SETNX 返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁。
 
import time
import redis
from conf.config import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD
 
class RedisLock:
    def __init__(self):
        self.conn = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, db=1)
        self._lock = 0
        self.lock_key = ""
    @staticmethod
    def my_float(timestamp):
        """
        Args:
            timestamp:
        Returns:
            float或者0
            如果取出的是None,说明原本锁并没人用,getset已经写入,返回0,可以继续操作。
        """
        if timestamp:
            return float(timestamp)
        else:
            #防止取出的值为None,转换float报错
            return 0
 
    @staticmethod
    def get_lock(cls, key, timeout=10):
        cls.lock_key = f"{key}_dynamic_lock"
        while cls._lock != 1:
            timestamp = time.time() + timeout + 1
            cls._lock = cls.conn.setnx(cls.lock_key, timestamp)
            # if 条件中,可能在运行到or之后被释放,也可能在and之后被释放
            # 将导致 get到一个None,float失败。
            if cls._lock == 1 or (
                            time.time() > cls.my_float(cls.conn.get(cls.lock_key)) and
                            time.time() > cls.my_float(cls.conn.getset(cls.lock_key, timestamp))):
                break
            else:
                time.sleep(0.3)
 
    @staticmethod
    def release(cls):
        if cls.conn.get(cls.lock_key) and time.time() < cls.conn.get(cls.lock_key):
            cls.conn.delete(cls.lock_key)
 
 
def redis_lock_deco(cls):
    def _deco(func):
        def __deco(*args, **kwargs):
            cls.get_lock(cls, args[1])
            try:
                return func(*args, **kwargs)
            finally:
                cls.release(cls)
        return __deco
    return _deco
 
 
@redis_lock_deco(RedisLock())
def my_func():
    print("myfunc() called.")
    time.sleep(20)
 
if __name__ == "__main__":
    my_func()
69.写一段 Python 使用 mongo 数据库创建索引的代码:
 
答:
 
# -*- coding: utf-8 -*-
# @Time : 2018/12/28 10:01 AM
# @Author : cxa
import pymongo
db_configs = {
    'type': 'mongo',
    'host': '地址',
    'port': '端口',
    'user': 'spider_data',
    'passwd': '密码',
    'db_name': 'spider_data'
}
 
 
class Mongo():
    def __init__(self, db=db_configs["db_name"], username=db_configs["user"],
                 password=db_configs["passwd"]):
        self.client = pymongo.MongoClient(f'mongodb://{db_configs["host"]}:{db_configs["port"]}')
        self.username = username
        self.password = password
        if self.username and self.password:
            self.db1 = self.client[db].authenticate(self.username, self.password)
        self.db1 = self.client[db]
 
    def add_index(self):
        """
          通过create_index添加索引
        """
        self.db1.test.create_index([('name', pymongo.ASCENDING)], unique=True)
 
    def get_index(self,):
        """
          查看索引列表
        """
        indexlist=self.db1.test.list_indexes()
        for index in indexlist:
            print(index)
 
if __name__ == '__main__':
    m = Mongo()
    m.add_index()
    print(m.get_index())
高级特性
 
70. 函数装饰器有什么作用?请列举说明?
 
答: 装饰器就是一个函数,它可以在不需要做任何代码变动的前提下给一个函数增加额外功能,启动装饰的效果。 它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。 下面是一个日志功能的装饰器
 
from functools import wraps
def log(label):
    def decorate(func):
       @wraps(func) 
       def _wrap(*args,**kwargs):
        try:
          func(*args,**kwargs)
          print("name",func.__name__)
        except Exception as e:
           print(e.args)
       return _wrap
    return decorate    
 
@log("info")
def foo(a,b,c):
     print(a+b+c)
     print("in foo")
 
#decorate=decorate(foo)   
 
if __name__ == '__main__':
    foo(1,2,3)
     #decorate()
71. Python 垃圾回收机制?
 
答:Python 不像 C++,Java 等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对 Python 语言来讲,对象的类型和内存都是在运行时确定的。这也是为什么我们称 Python 语言为动态类型的原因。
 
主要体现在下面三个方法:
 
1.引用计数机制 2.标记-清除 3.分代回收
 
72. 魔法函数 _call_怎么使用?
 
答: _call_ 可以把类实例当做函数调用。 使用示例如下
 
class Bar:
    def __call__(self, *args, **kwargs):
        print('in call')
 
 
if __name__ == '__main__':
    b = Bar()
    b()
73. 如何判断一个对象是函数还是方法?
 
答:看代码已经结果就懂了
 
from types import MethodType, FunctionType
 
 
class Bar:
    def foo(self):
        pass
 
 
def foo2():
    pass
 
 
def run():
    print("foo 是函数", isinstance(Bar().foo, FunctionType))
    print("foo 是方法", isinstance(Bar().foo, MethodType))
    print("foo2 是函数", isinstance(foo2, FunctionType))
    print("foo2 是方法", isinstance(foo2, MethodType))
 
 
if __name__ == '__main__':
    run()
输出
 
foo 是函数 False
foo 是方法 True
foo2 是函数 True
foo2 是方法 False
74. @classmethod 和 @staticmethod 用法和区别
 
答: 相同之处:@staticmethod 和@classmethod 都可以直接类名.方法名()来调用,不用在示例化一个类。 @classmethod 我们要写一个只在类中运行而不在实例中运行的方法。如果我们想让方法不在实例中运行,可以这么做:
 
def iget_no_of_instance(ins_obj):
    return ins_obj.__class__.no_inst
 
 
class Kls(object):
    no_inst = 0
 
    def __init__(self):
        Kls.no_inst = Kls.no_inst + 1
 
 
ik1 = Kls()
ik2 = Kls()
print(iget_no_of_instance(ik1))
@staticmethod 经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法
 
IND = 'ON'
 
 
class Kls(object):
    def __init__(self, data):
        self.data = data
 
    @staticmethod
    def check_ind():
        return (IND == 'ON')
 
    def do_reset(self):
        if self.check_ind():
            print('Reset done for:', self.data)
 
    def set_db(self):
        if self.check_ind():
            self.db = 'New db connection'
        print('DB connection made for: ', self.data)
 
 
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()
75. Python 中的接口如何实现?
 
答: 接口提取了一群类共同的函数,可以把接口当做一个函数的集合,然后让子类去实现接口中的函数。但是在 Python 中根本就没有一个叫做 interface 的关键字,如果非要去模仿接口的概念,可以使用抽象类来实现。抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。使用 abc 模块来实现抽象类。
 
76. Python 中的反射了解么?
 
答:Python 的反射机制设定较为简单,一共有四个关键函数分别是 getattr、hasattr、setattr、delattr。
 
77. metaclass 作用?以及应用场景?
 
答: metaclass 即元类,metaclass 是类似创建类的模板,所有的类都是通过他来 create 的(调用new),这使得你可以自由的控制创建类的那个过程,实现你所需要的功能。 我们可以使用元类创建单例模式和实现 ORM 模式。
 
78. hasattr()、getattr()、setattr() 的用法
 
答:这三个方法属于 Python 的反射机制里面的,hasattr 可以判断一个对象是否含有某个属性,getattr 可以充当 get 获取对象属性的作用。而 setattr 可以充当 person.name = "liming"的赋值操作。代码示例如下:
 
class Person():
    def __init__(self):
        self.name = "liming"
        self.age = 12
 
    def show(self):
        print(self.name)
        print(self.age)
 
    def set_name(self):
        setattr(Person, "sex", "男")
 
    def get_name(self):
        print(getattr(self, "name"))
        print(getattr(self, "age"))
        print(getattr(self, "sex"))
 
 
def run():
    if hasattr(Person, "show"):
        print("判断 Person 类是否含有 show 方法")
 
 
    Person().set_name()
    Person().get_name()
 
 
if __name__ == '__main__':
    run()
79. 请列举你知道的 Python 的魔法方法及用途。
 
答:
 
1 __init__:
类的初始化方法。它获取任何传给构造器的参数(比如我们调用 x = SomeClass(10, ‘foo’) , __init__就会接到参数 10 和 ‘foo’ 。 __init__在 Python 的类定义中用的最多。
 
2 __new__:
__new__是对象实例化时第一个调用的方法,它只取下 cls 参数,并把其他参数传给 __init__ 。 __new__很少使用,但是也有它适合的场景,尤其是当类继承自一个像元组或者字符串这样不经常改变的类型的时候.
 
3 __del__:
__new__和 __init__是对象的构造器, __del__是对象的销毁器。它并非实现了语句 del x (因此该语句不等同于 x.__del__())。而是定义了当对象被垃圾回收时的行为。 当对象需要在销毁时做一些处理的时候这个方法很有用,比如 socket 对象、文件对象。但是需要注意的是,当 Python 解释器退出但对象仍然存活的时候,__del__并不会 执行。 所以养成一个手工清理的好习惯是很重要的,比如及时关闭连接。
80. 如何知道一个 Python 对象的类型?
 
答:可以通过 type 方法
 
81. Python 的传参是传值还是传址?
 
答:Python 中的传参即不是传值也不是传地址,传的是对象的引用。
 
82. Python 中的元类 (metaclass) 使用举例
 
答:可以使用元类实现一个单例模式,代码如下
 
class Singleton(type):
    def __init__(self, *args, **kwargs):
        print("in __init__")
        self.__instance = None
        super(Singleton, self).__init__(*args, **kwargs)
 
    def __call__(self, *args, **kwargs):
        print("in __call__")
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance
 
class Foo(metaclass=Singleton):
    pass  # 在代码执行到这里的时候,元类中的__new__方法和__init__方法其实已经被执行了,而不是在 Foo 实例化的时候执行。且仅会执行一次。
 
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)
83. 简述 any() 和 all() 方法
 
答: any(x):判断 x 对象是否为空对象,如果都为空、0、false,则返回 false,如果不都为空、0、false,则返回 true。 all(x):如果 all(x) 参数 x 对象的所有元素不为 0、''、False 或者 x 为空对象,则返回 True,否则返回 False。
 
84. filter 方法求出列表所有奇数并构造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 

 
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(list(filter(lambda x: x % 2 == 1, a)))
其实现在不推荐使用 filter,map 等方法了,一般列表生成式就可以搞定了。
 
85. 什么是猴子补丁?
 
答: 猴子补丁(monkey patching):在运行时动态修改模块、类或函数,通常是添加功能或修正缺陷。猴子补丁在代码运行时内存中)发挥作用,不会修改源码,因此只对当前运行的程序实例有效。因为猴子补丁破坏了封装,而且容易导致程序与补丁代码的实现细节紧密耦合,所以被视为临时的变通方案,不是集成代码的推荐方式。大概是下面这样的一个效果
 
def post():
    print("this is post")
    print("想不到吧")
 
class Http():
    @classmethod
    def get(self):
        print("this is get")
 
 
def main():
    Http.get=post #动态的修改了 get 原因的功能,
 
if __name__ == '__main__':
    main()      
    Http.get() 
86. 在 Python 中是如何管理内存的?
 
答: 垃圾回收:Python 不像 C++,Java 等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对 Python 语言来讲,对象的类型和内存都是在运行时确定的。这也是为什么我们称 Python 语言为动态类型的原因(这里我们把动态类型可以简单的归结为对变量内存地址的分配是在运行时自动判断变量类型并对变量进行赋值)。
 
引用计数:Python 采用了类似 Windows 内核对象一样的方式来对内存进行管理。每一个对象,都维护这一个对指向该对对象的引用的计数。当变量被绑定在一个对象上的时候,该变量的引用计数就是 1,(还有另外一些情况也会导致变量引用计数的增加),系统会自动维护这些标签,并定时扫描,当某标签的引用计数变为 0 的时候,该对就会被回收。
 
内存池机制 Python 的内存机制以金字塔行,1、2 层主要有操作系统进行操作
 
第 0 层是 C 中的 malloc,free 等内存分配和释放函数进行操作
 
第 1 层和第 2 层是内存池,有 Python 的接口函数 PyMem_Malloc 函数实现,当对象小于 256K 时有该层直接分配内存
 
第 3 层是最上层,也就是我们对 Python 对象的直接操作
 
在 C 中如果频繁的调用 malloc 与 free 时,是会产生性能问题的.再加上频繁的分配与释放小块的内存会产生内存碎片。Python 在这里主要干的工作有:
 
如果请求分配的内存在 1~256 字节之间就使用自己的内存管理系统,否则直接使用 malloc。
 
这里还是会调用 malloc 分配内存,但每次会分配一块大小为 256k 的大块内存。
 
经由内存池登记的内存到最后还是会回收到内存池,并不会调用 C 的 free 释放掉以便下次使用。对于简单的 Python 对象,例如数值、字符串,元组(tuple 不允许被更改)采用的是复制的方式(深拷贝?),也就是说当将另一个变量 B 赋值给变量 A 时,虽然 A 和 B 的内存空间仍然相同,但当 A 的值发生变化时,会重新给 A 分配空间,A 和 B 的地址变得不再相同。
 
87. 当退出 Python 时是否释放所有内存分配?
 
答:不是的,循环引用其他对象或引用自全局命名空间的对象的模块,在 Python 退出时并非完全释放。
 
另外,也不会释放 c 库保留的内存部分
 
正则表达式
 
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值