基础部分
1. 为什么学习Python
家里有在这个IT圈子里面,也想让我接触这个圈子,然后给我建议学的Python,
然后自己通过百度和向有学过Python的同学了解了Python,Python这门语言,入门比较简单,
它简单易学,生态圈比较强大,涉及的地方比较多,特别是在人工智能,和数据分析这方面。
在未来我觉得是往自动化,人工智能这方面发展的,所以学习了Python
balabala.....
2. 通过什么途径学习Python
刚开始接触Python的时候,到网上里面跟着视频学基础,
再后来网上到看技术贴,然后看到有人推荐廖雪峰的Python教程,
练项目到GitHub上面找一些小项目学习
balabala....
3. 谈谈对Python和其他语言的区别
Python VS java
python
动态强类型,定义无需声明类型,崇尚鸭子类型
java
静态强类型,定义必须要声明定义类型
Python VS PHP
PHP 弱类型 面向web
Python 强类型 面向对象
Python VS C
Python 压倒性的代码简洁程度,缩进的使用。
C 大量的修饰词以及括号,代码量庞大
4. Python的优势
简易 :代码简单,易懂,易学
开源 可移植性强大
便于移植 :无需再次编译
编程方式多样 :函数编程,面向对象编程都支持 可扩展性和可嵌入性强大 丰富的库
动态类型 : 鸭子类型因此更加方便类型选择
5. python语言的缺点
运行速度比较C较弱
不能加密 : 开源性限制
构架选择太多: 没有官方框架
GIL : 全局解释器锁导致没有多线程
6. 简述解释型和编译型编程语言
解释型:就是边解释边执行
执行速度快、效率高;依赖编译器、跨平台性差些。如C、C++、Delphi、Pascal,Fortran
编译型:编译后再执行
执行速度慢、效率低;依赖解释器、跨平台性好。如Tcl、Perl、Ruby、VBScript、 JavaScript
7. Python的解释器种类以及相关特点?
CPython 官方版本的解释器:CPython。C语言 ,命令行下运行python就是启动CPython解释器。 CPython是使用最广的Python解释器。教程的所有代码也都在CPython下执行。 IPython IPython是基于CPython之上的一个交互式解释器,
IPython只是在交互方式上有所增强,但是执行Python代码的功能和CPython是完全一样的。
标识:
CPython用>>>作为提示符,而IPython用In [序号]:作为提示符。
PyPy
由Python写的解释器,执行速度最快。
PyPy采用JIT技术,对Python代码进行动态编译(注意不是解释),
绝大部分Python代码都可以在PyPy下运行,但是PyPy和CPython有一些是不同的,这就导致相同的Python代码在两种解释器下执行可能会有不同的结果。
Jython
Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。
IronPython
IronPython和Jython类似,只不过IronPython是运行在.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。
取舍:
使用最广泛的还是CPython。如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython,而是通过网络调用来交互,确保各程序之间的独立性。
8. 位和字节的关系
1字节 = 8 位
位(bit),数据存储是以“字节”(Byte)为单位,数据传输是以大多是以“位”(bit,又名“比特”)为单位,
一个位就代表一个0或1(即一个二进制),二进制是构成存储器的最小单位,每8个位(bit,简写为b)组成一个字节(Byte,简写为B),
字节是最小一级的信息单位
9. b、B、KB、MB、GB的关系
b --->位(bit) B --->字节 一个字节等于8位 1B = 8 bit 1kb = 1024 B 1 MB = 1024 KB 1 GB = 1024 MB
10. 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中多个库,
空格的使用 1. 各种右括号前不要加空格。 2. 逗号、冒号、分号前不要加空格。 3. 函数的左括号前不要加空格。如Func(1) 4. 序列的左括号前不要加空格。如list[2] 5. 操作符左右各加一个空格,不要为了对齐增加空格 6. 函数默认参数使用的赋值符左右省略空格 7. 不要将多句语句写在同一行,尽管使用‘;’允许
if/for/while语句中,即使执行语句只有一句,也必须另起一行 函数命名使用全部小写的方式,常量命名使用大写,类属性(方法和变量)使用小写 类的命名首字母大写
11. 进制转换
# 二进制转换成十进制-->int v = "0b1111011" b = int(v,2) print(b) # 123 # 十进制转换成二进制--->bin v2 = 18 print(bin(int(v2))) # 0b10010 # 八进制转换成十进制 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
12. 请编写一个函数实现将IP地址转换成一个整数
""" 请编写一个函数实现将IP地址转换成一个整数。 如 10.3.9.12 转换规则为: 10 00001010 3 00000011 9 00001001 12 00001100 再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ? """ def v1(addr): # 取每个数 id = [int(x) for x in addr.split(".")] print(id) return sum(id[i] << [24, 16, 8, 0][i] for i in range(4)) print(v1("127.0.0.1")) # [127, 0, 0, 1] # 2130706433
13. python递归的最大层数?
998
视情况而定,机器性能好的话也可以超出此上限
14. 求结果(and or or)
1. 求结果:1 or 3 print(1 or 3) # 1 2. 求结果:1 and 3 print(1 and 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 Flase and 1 print(0 or False and 1) # Flase 总结: # x or y 如果 x为真,则值为x, 否则为y # x and y 如果 x 为真,则值为 y,否则为 x
v1 = 1 or 3 -- 1 v2 = 1 and 3 -- 3 v3 = 0 and 2 and 1 -- 0 v4 = 0 and 2 or 1 -- 1 v5 = 0 and 2 or 1 or 4 -- 1 v6 = 0 or Flase and 1 -- False and:前后为真才为真 or:有一为真就为真 优先级:()>not>and>or 同等优先级下,从左向右
15 运算符
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
16 . ascii、unicode、utf-8、gbk 区别
python2 默认 ascii
python3 默认 utf-8
ascii 最多只能用8位来表示(一个字节),即:2**8 = 256,所以,ASCII码最多只能表示 256 个符号。 unicode 万国码,任何一个字符==两个字节 utf-8 万国码的升级版 一个中文字符==三个字节 英文是一个字节 欧洲的是 2个字节 gbk 国内版本 一个中文字符==2个字节 英文是一个字节
gbk 转 utf-8 需通过媒介 unicode
17. 字节码和机器码的区别
什么是机器码 机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。 通常意义上来理解的话,机器码就是计算机可以直接执行,并且执行速度最快的代码。 总结:机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写 什么是字节码 字节码(Bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。 字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。 总结:字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。
18. 简述变量命名规范
#1、以字母,数字,下划线任由结合 #2、不能以命名太长,不使用拼音,中文 #3、不能以数字开头 #4、不能用关键词
19. is 和 == 的区别
#is 比较的是内存地址 #== 比较的是值
is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。 == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。默认会调用对象的 __eq__()方法。
20. 三元运算写法和应用场景?
# 应用场景:简化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
21. Python3和Python2的区别?
1:打印时,py2需要可以不需要加括号,py3 需要 python 2 :print ('lili') , print 'lili' python 3 : print ('lili') python3 必须加括号 exec语句被python3废弃,统一使用exec函数 2:内涵 Python2:1,臃肿,源码的重复量很多。 2,语法不清晰,掺杂着C,php,Java,的一些陋习。 Python3:几乎是重构后的源码,规范,清晰,优美。 3、输出中文的区别 python2:要输出中文 需加 # -*- encoding:utf-8 -*- Python3 : 直接搞 4:input不同 python2 :raw_input python3 :input 统一使用input函数 5:指定字节 python2在编译安装时,可以通过参数-----enable-unicode=ucs2 或-----enable-unicode=ucs4分别用于指定使用2个字节、4个字节表示一个unicode; python3无法进行选择,默认使用 ucs4 查看当前python中表示unicode字符串时占用的空间: impor sys print(sys.maxunicode) #如果值是65535,则表示使用usc2标准,即:2个字节表示 #如果值是1114111,则表示使用usc4标准,即:4个字节表示 6: py2:xrange range py3:range 统一使用range,Python3中range的机制也进行修改并提高了大数据集生成效率 7:在包的知识点里 包:一群模块文件的集合 + __init__ 区别:py2 : 必须有__init__ py3:不是必须的了 8:不相等操作符"<>"被Python3废弃,统一使用"!=" 9:long整数类型被Python3废弃,统一使用int 10:迭代器iterator的next()函数被Python3废弃,统一使用next(iterator) 11:异常StandardError 被Python3废弃,统一使用Exception 12:字典变量的has_key函数被Python废弃,统一使用in关键词 13:file函数被Python3废弃,统一使用open来处理文件,可以通过io.IOBase检查文件类型
22. 用一行代码实现数值交换
a = 1 b = 2 a, b = b, a
23. 列列举布尔值为False的常见值?
0,“”,{},[],(),set()
0 False 负数 不成立的表达式 None 等
24. 字符串、列表、元组、字典每个常用的5个方法?
字符串
字符串用单引号(')或双引号(")括起来,不可变
1,find通过元素找索引,可切片,找不到返回-1 2,index,找不到报错。 3,split 由字符串分割成列表,默认按空格。 4,captalize 首字母大写,其他字母小写。 5,upper 全大写。 6,lower 全小写。 7,title,每个单词的首字母大写。 8,startswith 判断以什么为开头,可以切片,整体概念。 9,endswith 判断以什么为结尾,可以切片,整体概念。 10,format格式化输出 #format的三种玩法 格式化输出 res='{} {} {}'.format('egon',18,'male') ==> egon 18 male res='{1} {0} {1}'.format('egon',18,'male') ==> 18 egon 18 res='{name} {age} {sex}'.format(sex='male',name='egon',age=18) 11,strip 默认去掉两侧空格,有条件, 12,lstrip,rstrip 14,center 居中,默认空格。 15,count查找元素的个数,可以切片,若没有返回0 16,expandtabs 将一个tab键变成8个空格,如果tab前面的字符长度不足8个,则补全8个, 17,replace(old,new,次数) 18,isdigit 字符串由字母或数字组成 isalpha, 字符串只由字母组成 isalnum 字符串只由数字组成 19,swapcase 大小写翻转 20,for i in 可迭代对象。
字典
key: 输出所有的键 clear:清空 dic:删除的键如果没有则报错 pop:键值对删,有返回,没有原来的键会报错(自行设置返回键就不会报错) popitem:随机删键值对 del:删除的键如果没有则报错
update :更新数据 get: 不报错的查询 # 没有可以返回设定的返回值
列表
append:在后面添加。 Insert:按照索引添加, expend:迭代着添加。 pop 删除并作为返回值 remove 按照元素去删 clear 清空列表 del 删除列表 list.count(obj) - 统计某个元素在列表中出现的次数 list.index(obj) - 从列表中找出某个值第一个匹配项的索引位置 list.reverse() - 反向列表中元素 list.sort([func]) - 对原列表进行排序
元祖
1、cmp(tuple1, tuple2):比较两个元组元素。 2、len(tuple):计算元组元素个数。 3、max(tuple):返回元组中元素最大值。 4、min(tuple):返回元组中元素最小值。 5、tuple(seq):将列表转换为元组。
集合
set:创建集合 add: 添加元素 update:更新元素 clear:清空 pop:随机删除并返回 remove:指定删除 del: 删除集合
25. lambda表达式格式以及应用场景?
匿名函数:为了解决那些功能很简单的需求而设计的一句话函数 函数名 = lambda 参数 :返回值 #参数可以有多个,用逗号隔开 #匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值 #返回值和正常的函数一样可以是任意数据类型 lambda 表达式 temp = lambda x,y:x+y print(temp(4,10)) # 14 可替代: def foo(x,y): return x+y print(foo(4,10)) # 14
26. pass的作用
pass是空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句。
27. *arg和**kwarg作用
# 他们是一种动态传参,一般不确定需要传入几个参数时,可以使用其定义参数,然后从中取参 '*args':按照位置传参,将传入参数打包成一个‘元组’(打印参数为元组-- tuple) '**kwargs':按照关键字传参,将传入参数打包成一个‘字典’(打印参数为字典-- dict)
28. 谈谈Python的深浅拷贝?以及实现方法和应用场景。
浅拷贝只是增加了一个指针指向一个存在的地址,
数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)
深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存
数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)
采用浅拷贝的情况,释放内存,会释放同一内存,深拷贝就不会出现释放同一内存的错误
字典套字典、列表套字典、字典套列表,列表套列表,以及各种复杂数据结构的嵌套中,会出现拷贝后的数据发生变化导致源数据发生变化
import copy # 浅拷贝 l1 = [1,2,3,[11,22,33]] l2 = l1.copy() print(l2) #[1,2,3,[11,22,33]] l2[3][2]='aaa' print(l1) #[1, 2, 3, [11, 22, 'aaa']] print(l2) #[1, 2, 3, [11, 22, 'aaa']] l1[0]= 0 print(l1) #[0, 2, 3, [11, 22, 'aaa']] print(l2) #[1, 2, 3, [11, 22, 'aaa']] print(id(l1)==id(l2)) #False # 深拷贝 import copy l1 = [1, 2, 3, [11, 22, 33]] l2 = copy.deepcopy(l1) print(l1,'>>>',l2) # [1, 2, 3, [11, 22, 33]] >>> [1, 2, 3, [11, 22, 33]] l2[3][0] = 1111 print(l1,">>>",l2) # [1, 2, 3, [11, 22, 33]] >>> [1, 2, 3, [1111, 22, 33]]
29. Python垃圾回收机制?
# Python垃圾回收机制 Python垃圾回收机制,主要使用'引用计数'来跟踪和回收垃圾。 在'引用计数'的基础上,通过'标记-清除'(mark and sweep)解决容器对象可能产生的循环引用问题. 通过'分代回收'以空间换时间的方法提高垃圾回收效率。 '引用计数' PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。 当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除, 它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。 \优点:1.简单 2.实时性 \缺点:1.维护引用计数消耗资源 2.循环引用 '标记-清楚机制' 基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发, 遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记, 然后清扫一遍内存空间,把所有没标记的对象释放。 '分代技术' 分代回收的整体思想是: 将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”, 垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。
30. Python的可变类型和不可变类型?
可变数据类型:列表、字典、可变集合
不可变数据类型:数字、字符串、元组、不可变集合
31. 求结果
def multipliers(): return [lambda x:i*x for i in range(4)] print([m(2) for m in multipliers()])
#解释:
函数返回值为一个列表表达式,经过4次循环结果为包含四个lambda函数的列表, 由于函数未被调用,循环中的i值未被写入函数,经过多次替代,循环结束后i值为3, 故结果为:6,6,6,6
现有两个元组(('a'),('b')),(('c'),('d')),请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]
#匿名函数形式: l1=(('a'),('b')) l2=(('c'),('d')) ret=map(lambda n:{n[0]:n[1]},zip(l1,l2)) print(list(ret)) #列表表达式形式: l1=(('a'),('b')) l2=(('c'),('d')) print([{n[0]:n[1]} for n in zip(l1,l2)])
v = dict.fromkeys(['k1', 'k2'], []) v['k1'].append(666) print(v) v['k1'] = 777 print(v)
结果: {'k1': [666], 'k2': [666]} {'k1': 777, 'k2': [666]} 解释: Python 字典(Dictionary) fromkeys() 函数用于创建一个新字典,以序列seq中元素做字典的键,value为字典所有键对应的初始值,默认为None。
因为所有键对应同一个值,所以对键为‘k1’的值做了添加操作后,其他几个键的值也都添加了相同的值 v1 = dict.fromkeys(['k1', 'k2']) print(v1) # {'k1': None, 'k2': None} v2 = dict.fromkeys(['k1', 'k2'], []) print(v2) # {'k1': [], 'k2': []}
32. 列举常见的内置函数
map
根据函数对指定序列做映射 map()函数接收两个参数,一个是函数,一个是可迭代对象,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。 返回值: Python2 返回列表 Python3 返回迭代器 例子1: def mul(x): return x*x n=[1,2,3,4,5] res=list(map(mul,n)) print(res) #[1, 4, 9, 16, 25] 例子2:abs() 返回数字的绝对值 ret = map(abs,[-1,-5,6,-7]) print(list(ret)) # [1, 5, 6, 7]
filter
filter()函数接收一个函数 f(函数)和一个list(可迭代对象),这个函数 f的作用是对每个元素进行判断,返回 True或 False, filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。 def is_odd(x): return x % 2 == 1 v=list(filter(is_odd, [1, 4, 6, 7, 9, 12, 17])) print(v) #[1, 7, 9, 17]
reduce
''' reduce() 函数 reduce() 函数会对参数序列中元素进行累积 函数将一个数据集合(链表、元组等)中的所有数据进行下列操作 ''' 注意: Python3已经将reduce() 函数从全局名字空间里移除了,
它现在被放置在 fucntools 模块里,如果想要使用它,则需要通过引入 functools 模块来调用 reduce() 函数: from functools import reduce
def add(x,y): return x + y
print(reduce(add,[1,2,3,4,5])) # 15 print(reduce(lambda x, y: x+y, [1,2,3,4,5])) # 15 print(reduce(add,range(1,101))) # 5050
zip
# zip 拉链函数, # 将对象中对应的元素打包成一个个元组, # 然后返回由这些元组组成的列表迭代器。 # 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同。 print(list(zip([0,1,3],[5,6,7],['a','b']))) # [(0, 5, 'a'), (1, 6, 'b')]
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。 >>>a = [1,2,3] >>> b = [4,5,6] >>> c = [4,5,6,7,8] >>> zipped = zip(a,b) # 打包为元组的列表 [(1, 4), (2, 5), (3, 6)] >>> zip(a,c) # 元素个数与最短的列表一致 [(1, 4), (2, 5), (3, 6)] >>> zip(*zipped) # 与 zip 相反,可理解为解压,返回二维矩阵式 [(1, 2, 3), (4, 5, 6)]
isinstance\type
isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 与 type() 区别: type() 不会认为子类是一种父类类型,不考虑继承关系。 isinstance() 会认为子类是一种父类类型,考虑继承关系。 如果要判断两个类型是否相同推荐使用 isinstance()。
# 例一 a = 2 print(isinstance(a,int)) # True print(isinstance(a,str)) # False # type() 与 isinstance() 区别 class A: pass class B(A): pass print("isinstance",isinstance(A(),A)) # isinstance True print("type",type(A()) == A) # type True print('isinstance',isinstance(B(),A) ) # isinstance True print('type',type(B()) == A) # type False
33. 内置函数:map、reduce、filter的用法和区别
# map:遍历序列,为每一个序列进行操作,获取一个新的序列 a = ["123", "sb_sdsd", "sb_456"] b = map(lambda i: i+("sb"), a) print(list(b)) # ['123sb', 'sb_sdsdsb', 'sb_456sb'] # reduce:对于序列里面的所有元素进行累计操作,可带初始值 a = [1, 2, 3] from functools import reduce b = reduce(lambda i, j: i * j, a, 5) print(b) # 30 # filter:对序列里面的元素进行判断筛选,最终获取符合条件的序列。 a = ["123", "sb_sdsd", "sb_456"] b = filter(lambda i: i.startswith("sb"), a) print(list(b)) # ["sb_sdsd", "sb_456"]
34. 一行代码实现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)]))
35. 如何安装第三方模块?以及用过哪些第三方模块?
# a、可以在pycharm的settings里面手动下载添加第三方模块 # b、可以在cmd终端下用pip insatll 安装 # 用过的第三方模块:requests、pymysql、DBUtils等
requests,pymysql,DbUtils,SQLAlchemy
36. 常用模块都有那些?
re:正则 os:提供了一种方便的使用操作系统函数的方法。 sys:可供访问由解释器使用或维护的变量和与解释器进行交互的函数。 random:随机数 json:序列化 time:时间
37. re的match和search区别?
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
re.search 扫描整个字符串并返回第一个成功的匹配。
38. 什么是正则的贪婪匹配?
匹配一个字符串没有节制,能匹配多少就去匹配多少,直到没有匹配的为止
39. 求结果
a. [ i % 2 for i in range(10) ]
b. ( i % 2 for i in range(10) )
# a结果是一个列表生成式,结果是一个列表(i % 2为生成的元素): [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] # b结果是一个生成器
a. 1 or 2 b. 1 and 2 c. 1 < (2==2) d. 1 < 2 == 2
>>> 1 or 2 1 >>> 1 and 2 2 >>> 1 < (2==2) False >>> 1 < 2 == 2 True
40. def func(a,b=[]) 这种写法有什么坑?
def func(a,b = []): b.append(1) print(a,b) func(a=2) func(2) func(2) ''' 2 [1] 2 [1, 1] 2 [1, 1, 1] 函数的默认参数是一个list 当第一次执行的时候实例化了一个list 第二次执行还是用第一次执行的时候实例化的地址存储 所以三次执行的结果就是 [1, 1, 1] 想每次执行只输出[1] ,默认参数应该设置为None 函数传参为列表陷阱,列表是可变数据类型,可能会在过程中修改里面的值 '''
41. 如何实现 “1,2,3” 变成 [‘1’,’2’,’3’]
list("1,2,3".split(','))
42. 如何实现[‘1’,’2’,’3’]变成[1,2,3]
[int(x) for x in ['1','2','3']] a = ['1','2','3'] b = [int(i) for i in a] print(b) # [1, 2, 3]
43. a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的区别?
前两个元素是 int
最后一个元素是元祖
>>> a = (1) >>> type(a) <class 'int'> >>> a = (1,) >>> type(a) <class 'tuple'> >>>
44. a=[1,2,3,4,5],b=a和b=a[:],有区别么?
a = [1,2,3,4,5] b = a b1 = a[:] print(b) # [1, 2, 3, 4, 5] b.append(6) print("a",a) # a [1, 2, 3, 4, 5, 6] print("b",b) # b [1, 2, 3, 4, 5, 6] 传递引用 print("b1",b1) # b1 [1, 2, 3, 4, 5] 拷贝
45. 一个列表A=[2,3,4],Python如何将其转换成B=[(2,3),(3,4),(4,2)]?
A = [2,3,4]
B = zip(A, A[1:]+A[:1])
46. 如何用一行代码生成[1,4,9,16,25,36,49,64,81,100]
[i*i for i in range(1,11)]
47. 一行代码实现删除列表中重复的值
list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))
48. 如何在函数中设置一个全局变量
python中的global语句是被用来声明全局变量的。
x = 2 def func(): global x x = 1 return x func() print(x) # 1
49. logging模块的作用?以及应用场景?
logging
模块定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统
# 作用: 管理我们程序的执行日志,省去用print记录操作日志的操作,并且可以将标准输入输出保存到日志文件 # 场景: 爬虫爬取数据时,对爬取进行日志记录,方便分析、排错。
50. 请用代码简答实现stack
Stack() 创建一个新的空栈
push(item) 添加一个新的元素item到栈顶
pop() 弹出栈顶元素
peek() 返回栈顶元素
is_empty() 判断栈是否为空
size() 返回栈的元素个数
class Stack: def __init__(self): self.items = [] def is_empty(self): # 判断是否为空 return self.items == [] def push(self,item): # 加入元素 self.items.append(item) def pop(self): # 弹出元素 return self.items.pop() def peek(self): # 返回栈顶元素 return self.items[len(self.items)-1] def size(self): # 返回栈的大小 return len(self.items) if __name__ == "__main__": stack = Stack() stack.push("H") stack.push("E") stack.push("L") print(stack.size()) # 3 print(stack.peek()) # L print(stack.pop()) # L print(stack.pop()) # E print(stack.pop()) # H
51. 常用字符串格式化哪几种?
占位符%
%d 表示那个位置是整数;%f 表示浮点数;%s 表示字符串。
print('Hello,%s' % 'Python') print('Hello,%d%s%.2f' % (666, 'Python', 9.99)) # 打印:Hello,666Python10.00
format
print('{k} is {v}'.format(k='python', v='easy')) # 通过关键字 print('{0} is {1}'.format('python', 'easy')) # 通过关键字
f" {} "
python 3.7 加入的新特性,基于 format 的简易增强版
a = yangtuo b = f"{a} is good~~" print(a) # yangtuo is good~~
52. 简述 生成器、迭代器、可迭代对象 以及应用场景?
迭代器
内部有__next__和__iter__方法的对象,帮助我们向后一个一个取值,迭代器不一定是生成器
应用场景: - wtforms里面对form对象进行循环时,显示form中包含的所有字段 - 列表、字典、元组 (可以让一个对象被for循环)
生成器
一个函数内部存在yield关键字 应用场景: - rang/xrange - redis获取值 - conn = Redis(......) - v=conn.hscan_iter() # 内部通过yield 来返回值 - stark组件中 - 前端调用后端的yield
conn = Redis(...) def hscan_iter(self, name, match=None, count=None): """ Make an iterator using the HSCAN command so that the client doesn't need to remember the cursor position. ``match`` allows for filtering the keys by pattern ``count`` allows for hint the minimum number of returns """ cursor = '0' while cursor != 0: # 去redis中获取数据:12 # cursor,下一次取的位置 # data:本地获取的12条数数据 cursor, data = self.hscan(name, cursor=cursor,match=match, count=count) for item in data.items(): yield item
def index(request): data = [ {'k1':1,'name':'alex'}, {'k1':2,'name':'老男孩'}, {'k1':3,'name':'小男孩'}, ] new_data = [] for item in data: item['email'] = "[email protected]" new_data.append(item) return render(request,'xx.html',{'data':new_data})
装饰器
能够在不修改原函数代码的基础上,在执行前后进行定制操作,闭包函数的一种应用
场景: - flask 路由系统 - flask before_request - csrf - django 内置认证 - django 缓存
# 手写装饰器; import functools def wrapper(func): @functools.wraps(func) #不改变原函数属性 def inner(*args, **kwargs): 执行函数前 return func(*args, **kwargs) 执行函数后 return inner 1. 执行wapper函数,并将被装饰的函数当做参数。 wapper(index) 2. 将第一步的返回值,重新赋值给 新index = wapper(老index) @wrapper #index=wrapper(index) def index(x): return x+100
调用装饰器其实是一个闭包函数,为其他函数添加附加功能,不修改被修改的源代码和不修改被修饰的方式,装饰器的返回值也是一个函数对象。
比如:插入日志、性能测试、事物处理、缓存、权限验证等,有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
可迭代对象
字典,元祖,列表等
52. 用Python实现一个二分查找的函数。
二分查找算法:
简单的说,就是将一个列表先排序好,比如按照从小到大的顺序排列好,
当给定一个数据,比如3,查找3在列表中的位置时,
可以先找到列表中间的数li[middle]和3进行比较,
当它比3小时,那么3一定是在列表的右边,
反之,则3在列表的左边,比如它比3小,
则下次就可以只比较[middle+1, end]的数,
继续使用二分法,将它一分为二,直到找到3这个数返回或者列表全部遍历完成(3不在列表中) 优点:效率高,时间复杂度为O(logN); 缺点:数据要是有序的,顺序存储。
def binary_chop(alist, data): n = len(alist) if n < 1: return False mid = n // 2 if alist[mid] > data: return binary_chop(alist[0:mid], data) elif alist[mid] < data: return binary_chop(alist[mid + 1:], data) else: return True lis = [2, 4, 5, 12, 14, 23] print(binary_chop(lis, 2))
53. 谈谈你对闭包的理解?
# 闭包函数就是内部的函数调用外部函数的变量,常用于装饰器。 # 判断闭包函数的方法:__closure__,输出的__closure__有cell元素说明是闭包函数 # 闭包的意义与应用:
# 延迟计算
54. os和sys模块的作用?
os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
55. 如何生成一个随机数?
import random print(random.random()) # 用于生成一个0到1的随机符点数: 0 <= n < 1.0 print(random.randint(1, 1000)) # 用于生成一个指定范围内的整数
56. 如何使用python删除一个文件?
import os file = r'D:\test.txt' if os.path.exists(file): os.remove(file) print('delete success') else: print('no such file:%s' % file)
57. 谈谈你对面向对象的理解
先随便扯些和别的语言的对比 python 本身是支持函数式编程 和 面向对象式编程 c,java是只能基于面向对象 在简单说下面向对象的主要特点和好处 - 基础:面向对象本身拥有基础的三大特性 封装 将方法封装到类中 体现在 功能类上的整合 将数据封装到对象中 体现在类的对象初始化赋值等 继承 python 是支持多继承的 是python的一个特色,java c# 是不支持的 基于 mro 的顺序来决定继承顺序 多个类的对共同方法的,为避免重复编写,封装到父(基)类中 应用 : rest framework 中的视图类的继承非常多 多态 python 作为强类型的动态脚本语言,不支持多态,但是也不需要支持多态 在c# java里面必须要指定类型,当然也可以通过接口类实现目的 鸭子类型: python 中的参数可以传入任何类型的对象,不会对类型进行强制限制 说法: 如果我有个类,这个类的传入参数是不会有类型限制的 这体现了多态 我有多个类,这些都有个 send 方法 每个类的分别的实例化对象在调用 send 的时候 都是obj.send() 的一样的调用方式,但是却是执行的他内部的自己的 send 方法,这体现了多态性 - 进阶:魔法方法 __init__ 初始化 __new__ 创建对象 __call__ 对象() __str__ print(对象) __repr__ __iter__ 含有此方法且返回迭代器 代表此对象可迭代 __getattr__ 对象.xx __setattr__ __delattr__ 对象.del __setiter__ 对象["xx"] __getiter__ __deliter__ __mro__ 查看成员顺序 __dict__ 查看成员顺序 __add__ 对象相加的时候触发 __...__ 对象相减的时候触发 __...__ 对象相乘的时候触发 __...__ 对象相除的时候触发 __enter__ with 对象的开始前触发 __exit__ with 对象的结束时触发 应用: 在 SQLAlchemy 中有使用 - 高阶:metaclass 类的创建两种方法: class Foo():pass type("Foo",(object,),{ }) 指定创建类的 mtype class Foo(metaclass=MyType): # python 3 # __metaclass__ = MyType # python 2 pass MyType('Foo',(object,),{}) # 如果一类自己或基类中指定了metaclass # 那么该类就是由metaclass指定的type或mytype创建。 对于源码的阅读需要注意 是否指定了 metaclass 未指定直接看 __new__ 然后 __init__ 即可 如果指定了需要注意: 创建类 MyType.__init__ 创建对象 MyType.__call__ MyType.__new__ MyType.__init__
58. Python面向对象中的继承有什么特点
继承概念的实现方式主要有2类:实现继承、接口继承。 实现继承是指使用基类的属性和方法而无需额外编码的能力; 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法);
python 两种类:经典类 新式类 python3 新式类 —— 都默认继承object class Animal(object): == class Animal: python2 经典类和新式类 并存 class Animal: 经典类 —— 继承顺序 个别使用方法 class Animal(object): 新式类 继承分为单继承和多继承 Python是支持多继承的 如果没有指定基类,python的类会默认继承object类,
object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
class A: def get(self): self.say() def say(self): print('AAAAA') class B(A): def say(self): print('BBBBB') b = B() b.get() #输出结果为:BBBBB
59. 面向对象深度优先和广度优先是什么?
Python的类可以继承多个类,Python的类如果继承了多个类,那么其寻找方法的方式有两种
当类是经典类时,多继承情况下,会按照深度优先方式查找 py3
当类是新式类时,多继承情况下,会按照广度优先方式查找 py2
简单点说就是:经典类是纵向查找,新式类是横向查找
经典类和新式类的区别就是,在声明类的时候,新式类需要加上object关键字。在python3中默认全是新式类
60. 面向对象中super的作用?
用于子类继承基类的方法
61. 是否使用过functools中的函数?其作用是什么?
装饰器中,会用到;functools.wraps()主要在装饰器中用来装饰函数 Stark上下文管理源码中,走到视图阶段时有用到functools中的偏函数,
request = LocalProxy(partial(_lookup_req_object, 'request'))
62. 列举面向对象中带双下划线的特殊方法
# __getattr__ CBV django配置文件 wtforms中的Form()示例化中 将"_fields中的数据封装到From类中"
# __mro__ wtform中 FormMeta中继承类的优先级
# __dict__ 是用来存储对象属性的一个字典,其键为属性名,值为属性的值
# __new__ 实例化但是没有给当前对象 wtforms,字段实例化时返回:不是StringField,而是UnboundField est frawork many=Turn 中的序列化
# __call__ flask 请求的入口app.run() 字段生成标签时:字段.__str__ => 字段.__call__ => 插件.__call__
# __iter__ 循环对象是,自定义__iter__ wtforms中BaseForm中循环所有字段时定义了__iter__
# -metaclass 作用:用于指定当前类使用哪个类来创建 场景:在类创建之前定制操作 示例:wtforms中,对字段进行排序。
63. 如何判断是函数还是方法?
# 看他的调用者是谁,如果是类,需要传入参数self,这时就是一个函数; # 如果调用者是对象,不需要传入参数值self,这时是一个方法。 (FunctionType/MethodType)
print(isinstance(obj.func, FunctionType)) # False print(isinstance(obj.func, MethodType)) # True
64. 静态方法和类方法区别?
@property 将方法变成变量形式自动调用
@staticmethod 静态方法,类可以不用实例化就可以调用该方法 C.f(),当然也可以实例化后调用 C().f()。
@classmethod 类不需实例化就可以调用内部方法,直接类名.方法即可调用
Classmethod必须有一个指向类对象的引用作为第一个参数; @classmethod def class_func(cls): """ 定义类方法,至少有一个cls参数 """ print('类方法') --------------------------------------------------------- Staticmethod可以没有任何参数。 @staticmethod def static_func(): """ 定义静态方法 ,无默认参数""" print('静态方法')
65. 列举面向对象中的特殊成员以及应用场景
1. __doc__:表示类的描述信息。 2.__module__:表示当前操作的对象在那个模块; 3.__class__:表示当前操作的对象的类是什么。 4.__init__:构造方法,通过类创建对象时,自动触发执行。 5.__call__:对象后面加括号,触发执行。 6.__dict__:类或对象中的所有成员。 7.__str__:如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。 class Foo: def __str__(self): return 'aaa' obj = Foo() print(obj) # 输出:aaa 8.__getitem__、__setitem__、__delitem__:用于索引操作,如字典。以上分别表示获取、设置、删除数据。 9.__iter__:用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__。
66. 1、2、3、4、5 能组成多少个互不相同且无重复的三位数
题意理解:组成后的数值不相同,且组合的三个位数之间数字不重复。
使用python内置的排列组合函数(不放回抽样排列)
product 笛卡尔积 (有放回抽样排列)
permutations 排列 (不放回抽样排列)
combinations 组合,没有重复 (不放回抽样组合)
combinations_with_replacement 组合,有重复 (有放回抽样组合)
import itertools print(len(list(itertools.permutations('12345', 3)))) # 60
67. 什么是反射?以及应⽤用场景?
反射的核心本质就是以字符串的形式去导入个模块,利用字符串的形式去执行函数。
Django中的 CBV就是基于反射实现的。
rest framework里面的CBV
68. metaclass作用?以及应用场景?
# metaclass 实例 class MyType(type): def __init__(self,*args,**kwargs): super(MyType,self).__init__(*args,**kwargs) def __call__(cls, *args, **kwargs): obj = cls.__new__(cls) cls.__init__(obj,*args, **kwargs) return obj class Foo(object,metaclass=MyType): # metaclass 指定由谁来创建这个类 a1 = 123 def __init__(self): pass def __new__(cls, *args, **kwargs): return object.__new__(cls) def func(self): return 666 foo = Foo() # 创建类的时候会先执行 type 的 __init__ 方法 ,由type 的 __init__ 来创建类 # 当一个类在实例化时候,先执行 type 的 __call__ 方法 , __call__ 方法 的返回值就是实例化对象 # __call__ 内部调用: # 类.__new__ 方法 :创建对象 # 类.__init__ 方法 :对象初始化
69. 用尽量多的方法实现单例模式。
# 单例模式 '''单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。 通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。 如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。''' # 1、使用__new__方法 class MyClass(object): _instance = False def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = object.__new__(MyClass) return cls._instance # 2、共享属性 # 创建实例时把所有实例的__dict__指向同一个字典,这样它们具有相同的属性和方法. class Borg(object): _state = {} def __new__(cls, *args, **kw): ob = super(Borg, cls).__new__(cls, *args, **kw) ob.__dict__ = cls._state return ob class MyClass2(Borg): a = 1 # 3、装饰器版本 def singleton(cls, *args, **kw): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return getinstance @singleton class MyClass: ... # 4、import方法 # 作为python的模块是天然的单例模式 # mysingleton.py class My_Singleton(object): def foo(self): pass my_singleton = My_Singleton() # to use from mysingleton import my_singleton my_singleton.foo()
70. 装饰器器的写法以及应用场景。