Python企业面试题1 —— 基础篇

1. b、B、KB、MB、GB的关系?
b ---- 位(bit)
B ---- 字节(一个字节等于8位)
1 B = 8 bit
1 KB = 1024 B
1 MB = 1024 KB
1 GB = 1024 MB
2. PE8规范
1. 使用4个空格而不是tab键进行缩进。
2. 每行长度不能超过79。
3. 使用空行来间隔函数和类。
4. 必要时候,在每一行下写注释。
5. 使用文档注释,写出函数注释。
6. 在操作符和逗号之后使用空格,但是不要在括号内部使用。
7. 命名类和函数的时候使用一致的方式,比如使用 CamelCase 来命名类,使用 lower_case_with_underscores 来命名函数和方法。
8. 在类中总是使用 self 来作为默认。
9. 尽量不要使用魔法方法。
10. 默认使用UTF-8,甚至ASCII作为编码方式。
11. 换行可以使用反斜杠,最好使用圆括号。
12. 不要在一句 import 中多个库。

空格的使用
各种右括号前不要加空格。
逗号、冒号、分号前不要加空格。
函数的左括号前不要加空格。如Func(1)。
序列的左括号前不要加空格。如list[2]。
操作符左右各加一个空格,不要为了对齐增加空格。
函数默认参数使用的赋值符左右省略空格。
不要将多句语句卸载同一行,尽管使用';'允许。
if/for/while语句中,即使执行语句只有一句。也必须另起一行。

函数命名使用全部小写的方式,常量命名使用大写,类属性(方法和变量)使用小写。
类的命名首字母大写。
3. 通过代码实现如下进制间的转换。
python 复制代码
# 二进制转换成十进制 ------ int
v = "0b1111011"
b = int(v, 2)
print(b)	# 123

# 十进制转换成二进制 ------ bin
v2 = 18
print(bin(int(v2)))		# 0b00a0

# 八进制转换成十进制
v3 = "011"
print(int(v3))	# 11

# 十进制转换成八进制 ------ oct
v4 = 30
print(oct(int(v4)))     # 0o36

# 十六进制转换成十进制
v5 = "0x12"
print(int(v5, 16))  # 18

# 十进制转换成十六进制 ------ hex
v6 = 87
print(hex(int(v6))) # 0x57
4. python递归的最大层数?
998 主要还是要和执行的机器有关。
5. 求结果(and or)
1. 1 or 3
print(1 or 3)	# 1
2. 1 and 3
print(1 or 3)	# 3
3. 0 and 2 and 1
print(0 and 2 and 1)  # 0
4. 0 and 2 or 1
print(0 and 2 or 1)		# 1
5. 0 and 2 or 1 or 4
print(0 and 2 or 1 or 4)    # 1
6. 0 or False and 1
print(0 or False and 1)     # False
总结:
x or y 如果x为真,则值为x,否则为y。
x and y 如果x为真,则值为y,否则为x。

运算符:

1. 2 & 5
print(2 & 5)	# 10 & 101 => 000 => 0
2. 2 ^ 5
print(2 ^ 5)		# 10^101 => 111 => 1*2**0+1*2**1+1*2**2=1+2+4+7
6. ASCII、Unicode、UTF-8、GBK 的区别?
Python2内容进行编码默认是ASCII,而Python3对内容进行编码默认为UTF-8。
ASCII:最多只能用8位来表示,即2**8 = 256,所以,ASCII最多只能用8位来表示(一个字节),即2**8 = 256,所以,ASCII最多只能表示256个符号。
Unicode:万国码,任何一个字符==两个字节
UTF-8:万国码的升级版,1个中文字符==3个字节,英文是1个字节,欧洲的是2个字节。
GBK:国内版本,1个中文字符==3个字节,英文是1个字节
gbk转utf-8:需通过媒介Unicode
7. 三元运算写法和应用场景?
应用场景:简化if语句
# 关于三元运算
# 结果 + if + 条件 + else + 结果
result = 'gt' if 1 > 3 else 'lt'
print(result)	# lt
# 理解:如果条件为真,把if前面的值赋值给变量,否则把else后面的值赋值给变量

lambda表达式:
temp = lambda x, y : x+y
print(temp(4, 10))		# 14
可替代:
def foo(x, y):
	return x+y
print(foo(4, 10))	# 14
8. python2 和 python3 的区别?
1. 打印时,py2可以不加括号,也可以加括号,py3必须加括号。
py2:print('lili'), print 'lili'
py3:print('lili')

2. exec语句被py3废弃,统一使用exec函数。

3. 内涵:
py2: 1. 臃肿,源码的重复量多。
     2. 语法不清晰,掺杂着c,php,java的一些陋习。
py3:几乎是重构后的源码,规范,清晰,优美。

4. input不同
py2:raw_input
py3:input 统一使用input函数

5. 指定字节
py2在编译安装时,可以通过参数 --enable-unicode=ucs2 或者 --enable-unicode=ucs4 分别用于指定使用2个字节、4个字节表示一个unicode;
py3无法进行选择,默认选择使用ucs4;
查看当前py中表示unicode字符串时占用的空间;
import sys
print(sys.maxunicode)
# 如果值是65535,则表示使用ucs2标准,即:2个字节表示
# 如果值是1114111,则表示使用ucs4标准,即:4个字节表示

6.
py2:xrange
py3:range 统一使用range,py3中range的机制也可以进行修改并提高了大数据集生成效率。

7. 在包的知识点里
包:一群模块文件的集合 + __init__
区别:py2:必须有__init__
     py3:不是必须的了

8. 不相等操作符"<>"被py3废弃,统一使用"!="。

9. long整数类型被py3废弃,统一使用int。

10. 迭代器iterator的next()函数被py3,统一使用next(iterator)。

11. 异常StandarError被py3废弃,统一使用Exception。

12. 字典变量的has_key函数被py废弃,统一使用in关键词。

13. file函数被py3废弃,统一使用open来处理文件,可以通过io.IOBase检查文件类型。
9. py2和py3中 int 和 long 区别
在py3里,只有一种整数类型int,大多数情况下,和py2中的长整型类型。
10. xrange 和 range 的区别
都在循环时使用,xrange内存性能更好,xrange用法与range完全相同,range一个生成list对象,xrange是生成器
要生成很大的数字序列的时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间。
py2中:range([start,] stop[, step]), 根据start与stop指定的范围以及设定的步长,生成一个序列
xrange用法与range完全相同,所不同的是生成的不是一个数组,而是一个生成器。由上面的示例可以知道:要生成很大的数字序列的时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间,这两个基本上都是在循环的时候用。
py3:range()是像xrange()那样实现,xrange()被抛弃。
11. 文件操作时:xreadlines 和 readlines 的区别?
readlines:返回一个列表
xreadlines:返回一个生成器
12. 列举布尔值为 False 的常见值?
0,"",{},[],(),set(),False,负数,不成立的表达式,None等
13. pass、continue、break、exit的作用
pass:代码占位语句,不做任何操作
continue:结束本次循环,使程序进入到下一次循环
break:结束当前的循环
exit:结束当前程序
14:is 和 == 的区别
is比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。
==比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以。默认会调用对象的__eq__()方法。
a = 'lishi'
str1 = 'li'
str2 = 'shi'
str3 = 'str1 = str2'
print("id(a)", id(a))
print("id(str3)", id(str3))
# a == str3 True		==	---> 只需要内容相等
# a is str3 False		is	---> 只需要内存地址相等
# id(a)		38565848
# id(str3)		39110280
15. 谈谈py的深浅拷贝以及实现方法和应用场景?
浅拷贝只是增加了一个指针指向一个存在的地址,而深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存,采用浅拷贝的情况,释放内存,会释放同一内存,深拷贝就不会出现释放同一内存的错误。
一层的情况:
import copy
# 浅拷贝
li1 = [1, 2, 3]
li2 = li1.copy()
li1.append(4)
print(li1, li2)		# [1, 2, 3, 4][1, 2, 3]
# 深拷贝
li1 = [1, 2, 3]
li2 = copy.deepcopy(li1)
li1.append(4)
print(li1, li2)		# [1, 2, 3, 4][1, 2, 3]
多层的情况:
import copy
# 浅拷贝 指向共有的地址
li1 = [1, 2, 3, [4, 5], 6]
li2 = li1.copy()
li1[3].append(7)
print(li1, li2)		# [1, 2, 3, [4, 5, 7], 6][1, 2, 3, [4, 5, 7], 6]
# 深拷贝
li1 = [1, 2, 3, [4, 5], 6]
li2 = copy.deepcopy(li1)
li1.append(7)
print(li1, li2)		# [1, 2, 3, [4, 5, 7], 6][1, 2, 3, [4, 5], 6]
16. py垃圾回收机制?
1. 引用计数:
每一个对象都有ob_refcnt就是引用计数器,默认值为1,当有其他的变量引用对象时,引用计数器就会发生变化。
当一个引用计数器为0时,意味着没有人再使用这个对象,没有人是使用,就要进行垃圾回收。
2. 标记清除:
为了解决引用计数器的循环引用的问题
在py的内部某种情况下触发,到可能存在循环引用的单独链表进行扫描,检查是否有循环引用,如果存在循环引用,就让双方的引用计数器都-1,如果引用计数器都成0,则认为是垃圾,系统进行回收。
3. 分代回收:
将可能存在循环引用的对象维护三个链表
0代:0代中对象个数达到700扫描一次
1代:0代扫描10次,则1代扫描1次
2代:1代扫描10次,则2代扫描1次
4. 缓存机制:
为了避免重复使用的创建和销毁一些常见的对象,py在启动时维护了一个池子,存放:-5,-4,-3......256,这些数据占据的内存空间是确定的标记清除。
17. py的可变类型和不可变类型?
可变数据类型:列表、字典、可变集合
不可变数据类型:数字、字符串、元组、不可变集合
18. 一行代码实现9*9乘法表?
print('\n'.join([' '.join(['%s*%s=%-2s' % (j, i, i*j) for j in range(1, i+1)]) for i in range(1, 10)]))
19. 如何安装第三方模块?以及用过那些第三方模块?
1:pip包管理器
2:源码下载
   - 下载
   - 解压
- python setup.py build
- python setup.py install
用过的第三方模块:requests,pymysql,DbUtils,SQLAlchemy等。
20. 常用模块都有哪些?
re模块、os模块、json模块、time模块,爬虫里面的requests/beautifulsoup4(bs4)