面试:python基础 经典80问
面试:python基础 经典80问
1:为什么学习Python
公司建议使用Python,然后自己通过百度和向有学过Python的同学了解了Python。Python这门语言,入门比较简单,它简单易学,生态圈比较强大,涉及的地方比较多,特别是在人工智能,和数据分析这方面。在未来我觉得是往自动化,人工智能这方面发展的,所以学习了Python。
2:通过什么途径学习Python
自学,练项目,到GitHub上面找一些小项目学习。
3:谈谈对Python和其他语言的区别
Python属于解释型语言,当程序运行时,是一行一行的解释,并运行,所以调式代码很方便,开发效率高,还有龟叔给Python定位是任其自由发展、优雅、明确、简单,所以在每个领域都有建树,所有它有着非常强大的第三方库,
特点:
语法简洁优美,功能强大,标准库与第三方库都非常强大,而且应用领域也非常广;
可移植性,可扩展性,可嵌入性。
缺点:
运行速度慢。
- 解释型
- Python/php (java、C 编译型)
- 弱类型
- Python (java、C 强类型) - 动态语言
- Python (java、C 静态型)
(1)与Java相比:在很多方面,Python比java要简单,比如java中所有变量必须声明才能使用,而Python不需要声明,用少量的代码构建出很多功能;(高效的高级数据结构)
(2)与PHP相比:python标准包直接提供了工具,并且相对于PHP代码更易于维护;
(3)Python与C相比:
Python 和 C Python这门语言是由C开发而来
对于使用:Python的类库齐全并且使用简洁,如果要实现同样的功能,Python 10行代码可以解决,C可能就需要100行甚至更多.
对于速度:Python的运行速度相较与C,绝逼是慢了
Python的优势:
1、Python 易于学习;
2、用少量的代码构建出很多功能;(高效的高级数据结构)
3、Python 拥有最成熟的程序包资源库之一;
4、Python完全支持面向对象;
5、Python 是跨平台且开源的;
6、动态类型.
4:简述解释型和编译型编程语言
解释型:就是边解释边执行(Python,php)
编译型:编译后再执行(c、java、c#)
5:Python的解释器种类以及相关特点?
CPython
是官方版本的解释器:CPython。是使用C语言开发的,所以叫CPython。在命令行下运行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的字节码。
小结:
Python的解释器很多,但使用最广泛的还是CPython。如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython,而是通过网络调用来交互,确保各程序之间的独立性。
6:位和字节的关系
1字节 = 8 位
位(bit),数据存储是以“字节”(Byte)为单位,数据传输是以大多是以“位”(bit,又名“比特”)为单位,
一个位就代表一个0或1(即一个二进制),二进制是构成存储器的最小单位,每8个位(bit,简写为b)组成一个字节(Byte,简写为B),
字节是最小一级的信息单位。
7:b、B、KB、MB、GB的关系
b --->位(bit)
B --->字节 一个字节等于8位
1B = 8 bit
1kb = 1024 B
1 MB = 1024 KB
1 GB = 1024 MB
8:PEP8规范
1、使用4个空格而不是tab键进行缩进。
2、每行长度不能超过80
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语句中,即使执行语句只有一句,也必须另起一行
包名小写(不含下划线),函数名小写(可含下划线),常量名大写(可含下划线),类名驼峰写法,类属性小写(可含下划线)。
9:通过代码实现如下转换(进制之间转换)
#二进制转换成十进制-->int
v = "0b1111011"
b = int(v,2)
print(b) # 123
#十进制转换成二进制--->bin
v2 = 18
print(bin(int(v2)))
#0b10010
#八进制转换成十进制
v3 = "011"
print(int(v3,8))
#11
#十进制转换成八进制:---> oct
v4 = 30
print(oct(int(v4)))
#0o36
#十六进制转换成十进制:
v5 = "0x12"
print(int(v5,16))
#18
#十进制转换成十六进制:---> hex
v6 = 87
print(hex(int(v6)))
#0x57
10:请编写一个函数实现将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"))
结果:
11:python递归的最大层数?
998
12:求结果(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
运算符
1. 求结果:2 & 5(与)
print(2 & 5) # 10 & 101 => 000 => 0
2. 求结果:2 ^ 5即2 | 5(或)
print(2 ^ 5) # 10 ^ 101 => 111 => 1*2**0+1*2**1+1*2**2=1+2+4=7
13:ascii、unicode、utf-8、gbk 区别
Python2内容进行编码(默认ascii),而Python3对内容进行编码的默认为unicode。
ascii 最多只能用8位来表示(1个字节),即:2**8 = 256,所以,ASCII码最多只能表示 256 个符号。
unicode : 万国码,任何一个字符占2个字节
utf-8 : 万国码的升级版 一个中文字符占3个字节 英文是1个字节 欧洲的是2个字节
gbk : 国内版本 一个中文字符占2个字节 英文是1个字节
gbk 转 utf-8 需通过媒介 unicode
14:字节码和机器码的区别
机器码,学名机器语言指令,有时也被称为原生码,是电脑的CPU可直接解读的数据。
字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。
什么是机器码
机器码(machine code),学名机器语言指令,有时也被称为原生码(Native Code),是电脑的CPU可直接解读的数据。
通常意义上来理解的话,机器码就是计算机可以直接执行,并且执行速度最快的代码。
总结:机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩难懂,也比较难编写
什么是字节码
字节码(Bytecode)是一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。
字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。
总结:字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。
#is 比较的是内存地址
#== 比较的是值
#int 具有范围:-5---256
#对于int小数据池
范围:-5----256 创建的相间的数字,都指向同一个内存地址
#对于字符串
1、小数据池 如果有空格,那指向两个内存地址,
2、长度不能超过 20
3、不能用特殊字符
i = 'a'*20
j = 'a'*20
print(i is j) # True
i = "a"*21
j = "a"*21
print(i is j) # False
15:三元运算写法和应用场景?
应用场景:简化if语句
#关于三元运算
#关于三元运算
#结果+ if + 条件 + else + 结果
result='gt' if 1>3 else 'lt'
print(result) # lt
#理解:如果条件为真,把if前面的值赋值给变量,否则把else后面的值赋值给变量。
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
16:Python3和Python2的区别?
1:打印时,py2需要可以不需要加括号,py3 需要
python2 :print (‘lili’) , print ‘lili’
python3 : 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检查文件类型
17:用一行代码实现数值交换
a = 1
b = 2
a, b = b, a
18:Python3和Python2中int和long区别
在python3里,只有一种整数类型int。大多数情况下,和python2中的长整型类似。
19:xrange和range的区别
都在循环时使用,xrange内存性能更好,xrange用法与range完全相同,range一个生成list对象,xrange是生成器。
要生成很大的数字序列的时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间。
在Python2中:
range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个序列
xrange用法与range完全相同,所不同的是生成的不是一个数组,而是一个生成器。
由上面的示例可以知道:要生成很大的数字序列的时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间,这两个基本上都是在循环的时候用。
在 Python3 中,range() 是像 xrange() 那样实现,xrange()被抛弃。
20:文件操作时:xreadlines和readlines的区别?
readlines 返回一个列表
xreadlines 返回一个生成器
21:列列举布尔值为False的常见值?
0,“”,{},[],(),set(),False,负数,不成立的表达式,None,等。
22:字符串、列表、元组、字典每个常用的5个方法?
字符串:
字符串用单引号(')或双引号(")括起来,不可变。
s.strip(c):去除空格或指定的字符c;lstrip/rstrip;
s.zfill(w):右对齐,宽度小于w用0前补;
s.ljust(w,c):左对齐,宽度w,填充符c;rjust()右对齐。
s.join(q):用"s"将序列"q"中的元素串起来;
s.partition(sep):以sep为分隔符,把字符串分割,返回一个元组(包含分割符);
s.split(sep=None, maxsplit=-1):把字符串以sep为分隔符分割,maxsplit为分割次数,返回一个列表(不包含分割符);
s.find(t):返回t的最左位置,未找到,返回-1;
s.index(t):返回t的最左位置,未找到,返回ValueError异常;
s.capitalize():第一个字母变大写;
s.title():每个单词首字母大写;
s.center(width, fillchar=None):字符串内容居中,在给定的字符串长度width中内容居中,两边用提供的字符fillchar填充,fillchar默认为空;
s.count(sub, start=None, end=None):在指定位置start与end之间,计算sub字符的数量;
s.endswith(suffix, start=None, end=None):判断字符串在start与end位置之间是不是以某个子序列suffix结尾,类似方法还可有startwith();
s.replace(old, new, count=None):把字符串中某个子序列old替换成一个新序列new,count是替换数,返回一个新字符串;
s.isdigit():判断是否全是数字;
s.isalpha():判断是否全是字母;
s.isalnum():判断是否包含字母或数字;
s.isspace():判断是否是空字符串;
s[start:stop:step]:切片,截取子字符串。
字典:
1:无序(不能索引) 2:数据关联性强 3:键值对,键值对。唯一一个映射数据类型。
字典的键必须是可哈希的,不可变类型。
在同一个字典中,键(key)必须是唯一的。
列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取
clear(self)#:清除字典中的所有元素。
copy(self)#:复制一份元组,相当于一次浅拷贝。
fromkeys(self, iter, value=None)#:分别以iter中的元素为键,以value为值,创建一个字典。
get(self, k, d=None)#:获取字典中键为k的值,如果字典中不包含k,则给出d值,d默认为None。
items(self)#:遍历字典的一个方法,把字典中每对key和value组成一个元组,并把这些元组放在一个类似列表的dict_items中返回。
keys(self)#:遍历字典键keys的一个方法,返回一个类似列表的dict_keys,与items方法用法相同。
values(self)#:遍历字典值value的一个方法,返回一个类似列表的dict_values,与items方法用法相同。
pop(self, k, d=None)#:弹除并返回字典中键为k的值。
popitem(self)#:从字典中随机取出一组键值,返回一个新的元组。
setdefault(self, k, default=None)#:从字典中获取键为k的值,当存在k时,功能和get基本一致,当字典中不存在k时,在原字典上添加键为k、值为default的项,并返回default值。
update(self, E=None, **F)#:给字典新增元素,没有返回值。用法:dict.update(dict2)。
列表:
索引,切片,加,乘,检查成员。
1、List写在方括号之间,元素用逗号隔开。
2、和字符串一样,list可以被索引和切片。
3、List可以使用+操作符进行拼接。
4、List中的元素是可以改变的。
append(self, p_object)#:在原有列表最后位置上追加新元素到列表,不生成新的列表。
clear(self)#:清空列表里面的元素,不生成新列表。
copy(self)#:复制一份列表,相当于一次浅拷贝。
extend(self, iterable)#:把iterable中的每个元素扩展成列表的元素,iterable可以是字符串、列表、集合、元组、字典。
index(self, value, start=None, stop=None)#:查找列表中value元素索引位置,start与stop参数是查找起始与结束位置,默认为None。
insert(self, index, p_object)#:在列表index索引位置插入元素p_object,当index大于列表包含的元素个数时,在最后位置插入元素。
pop(self, index=None)#:从列表中取出index位置的值,index默认为None,此时弹除并返回列表中最后一个值。
remove(self, value)#:移除列表中第一个出现的value元素,value元素不存在列表中时,则抛出ValueError。
reverse(self)#:反转列表元素的位置。
sort(self, key=None, reverse=False)#:给列表中的元素排序,改变原列表!reverse默认False(升序)。【而sorted()函数是生成副本】。
[start:stop:step]#:切片,从列表中取出一部分元素生成一个新列表,start与stop默认为None,step表示步长值,默认是一个接着一个切取,
#如果为2,则表示进行隔一取一操作。步长值为正时表示从左向右取,如果为负,则表示从右向左取。步长值不能为0。
#索引[index]:获取索引位置index的值。
元组:
()元组的元素不能修改。
1、与字符串一样,元组的元素不能修改。
2、元组也可以被索引和切片,方法一样。
3、注意构造包含0或1个元素的元组的特殊语法规则。
4、元组也可以使用+操作符进行拼接。
count(self, value)#:统计元组中包含value元素的数量,返回一个int值。
index(self, value, start=None, stop=None)#:索引,查找元组中value元素第一个出现的位置,start与stop参数是查找起始与结束位置,默认为None。
[start:stop:step]#:切片操作。
Set(集合):
集合(set)是一个无序不重复元素的序列。
可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
add(self, *args, **kwargs)#:在集合里添加一个元素,不生成新的集合。
clear(self, *args, **kwargs)#:清空集合里面的元素,不生成新的集合。
copy(self, *args, **kwargs)#:浅拷贝集合,返回一个新集合。
difference(self, *args, **kwargs)#:传入一个或多个参数集合对比,返回一个与参数集合不一样元素的集合。
discard(self, *args, **kwargs)#:删除集合中的某个元素,如果这个元素没有在集合中,不做操作。
isdisjoint(self, *args, **kwargs)#:对比两个集合,若空交集则返回True,没有则返回False。
issubset(self, *args, **kwargs)#:判断集合的包含关系,是否是参数集合的子集。
pop(self, *args, **kwargs)#:从集合中随机(因集合无序)弹除并返回一个元素,如果集合为空,则报TypeError错误。
remove(self, *args, **kwargs)#:移除集合中的一个元素,这个元素必须在集合中,如果不在,则报TypeError错误。
union(self, *args, **kwargs)#:两个集合拼接返回一个新集合。
update(self, *args, **kwargs)#:更新集合,添加集合中没有的新元素,不返回新集合。
23: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
24:pass的作用
pass是空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句。
25:*arg和kwargs作用**
*arg 代表位置参数,它会接收任意多个参数并把这些参数作为元祖传递给函数。
**kwargs 代表的关键字参数,返回的是字典,位置参数一定要放在关键字前面。
26. is和==的区别
a = 'lishi'
str1 = "li"
str2 = "shi"
str3 = str1 + str2
print("a == str3",a == str3)
print("a is str3",a is str3)
print("id(a)",id(a))
print("id(str3)",id(str3))
#a == str3 ,True == ---> 只需要内容相等
#a is str3 ,False is ---> 只需要内存地址相等
#id(a) 38565848
#id(str3) 39110280
is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。
== 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。默认会调用对象的 eq()方法。
27:谈谈Python的深浅拷贝?以及实现方法和应用场景。
浅拷贝只是增加了一个指针指向一个存在的地址,而深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存。采用浅拷贝的情况,释放内存,会释放同一内存,深拷贝就不会出现释放同一内存的错误。
一层的情况:
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[3].append(7)
print(li1, li2) # [1, 2, 3, [4, 5, 7], 6] [1, 2, 3, [4, 5], 6]
28:Python垃圾回收机制?
引用计数
标记清除
分代回收
29:Python的可变类型和不可变类型?
可变数据类型:列表、字典、集合
不可变数据类型:数字、字符串、元组
30:求结果
def a():
return [lambda x:i*x for i in range(4)]
b=a() #返回个函数列表
print(b[1](1)) ---- 3
print(type(b),b) ----
print([m(1) for m in a()]) ---- [3,3,3,3]
print([i*i for i in [1,2,3]]) ---- [1,4,9]
#解释:
函数返回值为一个列表表达式,经过4次循环结果为包含四个lambda函数的列表,
由于函数未被调用,循环中的i值未被写入函数,经过多次替代,循环结束后i值为3。
请修改a的定义来产生期望的结果(0,2,4,6)。
def a():
return (lambda x:i*x for i in range(4)) #返回一个生成器表达式
print([m(2) for m in a()])
2)
现有两个元组((‘a’),(‘b’)),((‘c’),(‘d’)),请使用python匿名函数生成列表[{‘a’:‘c’},{‘b’:‘d’}]
#匿名函数形式:
li1=(('a'),('b'))
li2=(('c'),('d'))
ret=map(lambda n:{n[0]:n[1]},zip(li1,li2))
print(list(ret))
#列表表达式形式:
li1=(('a'),('b'))
li2=(('c'),('d'))
print([{n[0]:n[1]} for n in zip(li1,li2)])
31:求结果
v = dict.fromkeys(['k1', 'k2'], [])
v['k1'].append(666)
print(v)
结果:
{'k1': [666], 'k2': [666]}
解释:
Python 字典(Dictionary) fromkeys() 函数用于创建一个新字典,以序列seq中元素做字典的键,value为字典所有键对应的初始值,默认为None。
v1 = dict.fromkeys(['k1', 'k2'])
print(v1) # {'k1': None, 'k2': None}
v2 = dict.fromkeys(['k1', 'k2'], [])
print(v2) # {'k1': [], 'k2': []}
32:列举常见的内置函数
abs()
返回数字的绝对值。
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]
map与filter总结
filter 与 map 总结
共同点:
#参数: 都是一个函数名 + 可迭代对象
#返回值: 都是返回可迭代对象
区别:
#filter 是做筛选的,结果还是原来就在可迭代对象中的项
#map 是对可迭代对象中每一项做操作的,结果不一定是原来就在可迭代对象中的
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插入代码片
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)]
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
33:filter、map、reduce的作用?
内置函数:map、reduce、filter的用法和区别
map:根据函数对指定序列做映射
map
参数
接收两个参数:一个是函数,一个是序列(可迭代对象)
返回值
Python2 返回列表
Python3 返回迭代器
#例子:
#abs() 函数返回数字的绝对值
#新的内容的个数等于原内容的个数
ret = map(abs,[-1,-5,6,-7])
print(list(ret))
#[1, 5, 6, 7]
filter:过滤函数 新的内容少于等于原内容的时候。才能使用filter
filter() 函数用于过滤序列,过滤不符合条件的元素,返回由符合条件元素组成的心列表
参数:
function 函数
iterable 可迭代对象
返回值:
返回列表
#筛选大于10的数
def is_odd(x):
if x>10:
return True
ret = filter(is_odd,[1,4,5,7,8,9,76]) # 为迭代器
print(list(ret))
#[76]
reduce:对于序列内所有元素进行累计操作
‘’’
reduce() 函数
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)))
#505
34:一行代码实现9*9乘法表
multi = '\n'.join([' '.join(['%s*%s=%2s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10)])
print(multi)
提示:核心是两层嵌套列表生成式–> [[… for …] for …],然后用空格去拼接内层列表元素,再用换行去拼接外层列表元素。
35:如何安装第三方模块?以及用过哪些第三方模块?
1:pip包管理器
2:源码下载
-下载
-解压
-python setup.py build
-python setup.py install
用过的第三方模块:pymysql,BeautifulSoup,SQLAlchemy,Scrapy,Django,memcached等。
36:常用内置模块都有那些?
re,os,sys,json,time,datetime,random,logging等。
37:re的match和search区别?
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
re.search 扫描整个字符串并返回第一个成功的匹配。
38:什么是正则的贪婪匹配?
匹配一个字符串没有节制,能匹配多少就去匹配多少,知道没有匹配的为止。
39:求结果
a. [ i % 2 for i in range(10) ]
print([ i % 2 for i in range(10) ]) # [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
print([ i for i in range(10) ]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print([ 10 % 2]) # [0]
#%是个取余数运算符。
b. ( i % 2 for i in range(10) )
print(( i % 2 for i in range(10) ))
#<generator object <genexpr> at 0x00000000020CEEB8> 生成器
#在Python中,有一种自定义迭代器的方式,称为生成器(Generator)。
#定义生成器的两种方式:
#1.创建一个generator,只要把一个列表生成式的[]改成(),就创建了一个generator:
#generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,
没有更多的元素时,抛出StopIteration的错误。
#2.定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,
而是一个generator
40:求结果
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
41:def func(a,b=[]) 这种写法有什什么坑?
def func(a,b = []):
b.append(1)
print(a,b)
func(a=2)
func(2)
func(2)
函数的默认参数是一个list 当第一次执行的时候实例化了一个list
第二次执行还是用第一次执行的时候实例化的地址存储
所以三次执行的结果就是 [1, 1, 1] 想每次执行只输出[1] ,默认参数应该设置为None,然后初始化b=[]
‘’’
42:如何实现 “1, 2, 3” 变成 [‘1’, ‘2’, ‘3’]
list("1,2,3".split(','))
43:如何实现[‘1’,’2’,’3’]变成[1,2,3]
[int(x) for x in ['1','2','3']]
44:a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 c = [(1,),(2,),(3,) ] 的区别?
a等于b,a不等于c
补充:
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:如何用一行代码生成[1,4,9,16,25,36,49,64,81,100]
[i*i for i in range(1,11)]
46:一行代码实现删除列表中重复的值
list(set([1, 2, 3, 4, 45, 1, 2, 343, 2, 2]))
47:如何在函数中设置一个全局变量
python中的global语句是被用来声明全局变量的。
x = 2
def func():
global x # global用于函数中
x = 1
return x
func()
print(x) # 1
48:logging模块的作用?以及应用场景?
logging
模块定义的函数和类为应用程序和库的开发实现了一个灵活的事件日志系统。
作用:可以了解程序运行情况,是否正常
在程序的出现故障快速定位出错地方及故障分析
49:请用代码简答实现stack
• Stack() 创建一个新的空栈
• push(item) 添加一个新的元素item到栈顶
• pop() 弹出栈顶元素
• peek() 返回栈顶元素
• is_empty() 判断栈是否为空
• size() 返回栈的元素个数
#实现一个栈stack,后进先出
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
50:常用字符串格式化哪几种?
1.占位符%
%d 表示那个位置是整数;%f 表示浮点数;%s 表示字符串。
print('Hello,%s' % 'Python')
print('Hello,%d%s%.2f' % (666, 'Python', 9.99)) # 打印:Hello,666Python10.00
2.format
print('{k} is {v}'.format(k='python', v='easy')) # 通过关键字
print('{0} is {1}'.format('python', 'easy')) # 通过关键字
51:简述 生成器、迭代器、可迭代对象 以及应用场景?
迭代器
含有__iter__和__next__方法 (包含__next__方法的可迭代对象就是迭代器)
生成器
包括含有yield这个关键字,生成器也是迭代器,调动next把函数变成迭代器。
应用场景:
range/xrange
- py2:xrange(1000000) 生成器
- py3:range(1000000)生成器
- redis获取值
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
可迭代对象
一个类内部实现__iter__方法且返回一个迭代器。
装饰器
装饰器:
能够在不修改原函数代码的基础上,在执行前后进行定制操作,闭包函数的一种应用。
场景:
- 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
- 执行wapper函数,并将被装饰的函数当做参数。 wapper(index)
- 将第一步的返回值,重新赋值给 新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);
缺点:数据要是有序的,顺序存储。
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def bin_search(arr, find):
mid = len(arr) // 2
if len(arr) >= 1:
if find < arr[mid]:
bin_search(arr[:mid], find)
elif find > arr[mid]:
bin_search(arr[mid + 1:], find)
else:
# return mid # 小心这个坑!递归中不能用return!!
print(mid)
else:
# return '-1' # 小心这个坑!递归中不能用return!!
print("not found !")
53:谈谈你对闭包的理解?
def foo():
m=3
n=5
def bar():
a=4
return m+n+a
return bar
>>>bar = foo()
>>>bar()
12
说明:
bar在foo函数的代码块中定义。我们称bar是foo的内部函数。
在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。
简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。
54:os和sys模块的作用?
os模块 负责程序与操作系统的交互,提供了访问操作系统底层的接口。
sys模块 负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
#********************** os内置模块 **********************#
os.name #查看当前操作系统的名称。windows平台下返回"nt",Linux则返回"posix"
os.curdir #等价于".",表示当前目录
os.pardir #等价于"..",表示上级目录
os.getcwd() #取当前工作目录名
os.chdir() #切换工作目录,相当于shell下的cd
os.chmod() #改变目录权限
os.rename('oldname', 'newname') #重命名文件
os.walk() #生成目录树下的所有文件名
os.mkdir/makedirs('dirname') #创建目录/多层目录
os.rmdir/removedirs('dirname') #删除目录/多层目录
os.remove('path/filename') #删除文件
os.listdir('dirname') #列出指定目录的文件
os.path.basename('path/filename') #去掉目录,返回文件名
os.path.dirname('path/filename') #去掉文件名,返回目录
os.path.join(path1[,path2[,...]]) #将分离的各部分组拼接成一个路径名
os.path.split('path/filename') #返回(dirname(), basename())元组
os.path.splitext('path/filename') #返回(filename, '.扩展名')元组
os.path.getatime/ctime/mtime() #分别返回最近访问、创建、修改时间(时间戳)
os.path.getsize('path/filename') #返回文件大小(字符数)
os.path.exists() #是否存在
os.path.isabs() #是否为绝对路径
os.path.isdir() #是否为目录
os.path.isfile() #是否为文件
#********************** sys内置模块 **********************#
sys.argv #命令行参数List,第一个元素是程序本身路径
sys.hexversion #获取Python解释程序的版本值,16进制格式如:0x020403F0
sys.version #获取Python解释程序的版本信息
sys.maxsize #最大的Int值
sys.maxunicode #最大的Unicode值
sys.modules #返回系统导入的模块字段,key是模块名,value是模块
sys.path #返回模块的搜索路径,初始化时使用'PYTHONPATH'环境变量的值
sys.platform #返回操作系统平台名称
sys.exec_prefix #返回平台独立的python文件安装的位置
sys.byteorder #本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little'
sys.copyright #记录python版权相关的东西
sys.api_version #解释器的C的API版本
sys.stdin #标准输入
sys.stdout #标准输出
sys.stderr #错误输出
sys.modules.keys() #返回所有已经导入的模块列表
sys.exc_info() #获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息
sys.exit(n) #退出程序,正常退出时exit(0)
sys.exc_clear() #用来清除当前线程所出现的当前的或最近的错误信息
sys.stdin input()#调用了sys.stdin.read()
sys.stdout write()#调用了sys.stdout.write()
sys.stderr
55:如何生成一个随机数?
import random
print(random.random()) # 用于生成一个0到1的随机浮点数: 0 <= n < 1.0
print(random.randint(1, 1000)) # 用于生成一个指定范围内的整数
print(random.uniform(1, 1000)) # 用于生成一个指定范围内的浮点数
56:如何使用python删除一个文件?
os.remove(file) # 删除文件
os.rmdir(dir) # 删除目录
57:谈谈你对面向对象的理解
三大特性以及解释?
面对对象是一种编程思想,以类的眼光来来看待事物的一种方式。将有共同的属性和方法的事物封装到同一个类下面。
继承:将多个类的共同属性和方法封装到一个父类下面,然后在用这些类来继承这个类的属性和方法。
封装:将有共同的属性和方法封装到同一个类下面。
• 第一层面:创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装;
• 第二层面:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
多态:Python天生是支持多态的。指的是基类的同一个方法在不同的派生类中有着不同的功能(重写体现了多态)。
58:Python面向对象中的继承有什么特点
继承概念的实现方式主要有2类:直接继承、接口继承。
直接继承是指使用基类的属性和方法而无需额外编码的能力;
接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构父类方法);
python 两种类:经典类 新式类
python3 新式类 都默认继承object
python2 经典类和新式类 并存
class Animal: 经典类 – 继承顺序 个别使用方法
class Animal(object): 新式类
继承分为单继承和多继承
Python是支持多继承的。
如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
补充继承的应用
1、对象可以调用自己本类和父类的所有方法和属性, 先调用自己的 自己没有才调父类的。谁(对象)调用方法,方法中的self就指向谁
class Foo:
def __init__(self):
self.func()
def func(self):
print('Foo.func')
class Son(Foo):
def func(self):
print('Son.func')
s = Son()
# Son.func
========================================================
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的类如果继承了多个类,那么其寻找方法的方式有两种:
当类是经典类时,多继承情况下,会按照深度优先方式查找 --py2
当类是新式类时,多继承情况下,会按照广度优先方式查找 --py3
简单点说就是:经典类是纵向查找,新式类是横向查找。
经典类和新式类的区别就是,在声明类的时候,新式类需要加上object关键字。在python3中默认全是新式类。
60:面向对象中super的作用?
用于子类继承父类的方法,会将父类的方法完全继承下来。
class Foo():
def bar(self):
print('from parent class.')
class Child(Foo):
def bar(self):
super(Child, self).bar() # 继承了父类的方法
print('from child class.') # 增加了自己的功能
c = Child()
c.bar()
#结果:
from parent class.
from child class.
61:是否使用过functools中的函数?其作用是什么?
用于保护装饰器传入的函数。
import functools
def deco(func):
@functools.wraps(func) # 加在最内层函数正上方
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@deco
def index():
'''哈哈哈哈'''
x = 10
print('from index')
print(index.__name__)
print(index.__doc__)
#加@functools.wraps
#index
#哈哈哈哈
#不加@functools.wraps
#wrapper
#None
62:列举面向对象中带双下划线的特殊方法,如:new、init
__new__:创建实例
__init__:初始化实例
__call__:实例对象加( )会执行def __call__:... 方法里边的内容。
__del__:析构方法,当对象在内存中被释放时,自动触发执行。如当 del obj 或者应用程序运行完毕时,执行该方法里边的内容。
__enter__和__exit__:出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量;with中代码块执行完毕时执行__exit__里边的内容。
__module__:表示当前操作的对象在那个模块 obj.__module__
__class__ :表示当前操作的对象的类是什么 obj.__class__
__doc__:类的描述信息,该描述信息无法被继承
__str__:改变对象的字符串显示 print函数 --->obj.__str__()
__repr__:改变对象的字符串显示 交互式解释器 --->obj.__repr__()
__format__:自定制格式化字符串
__slots__:一个类变量 用来限制实例可以添加的属性的数量和类型
__setitem__,__getitem,__delitem__:
class Foo:
def __init__(self,name):
self.name=name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key]=value
def __delitem__(self, key):
print('del obj[key]时,我执行')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时,我执行')
self.__dict__.pop(item)
f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
__setattr__,__delattr__,__getattr__
63:如何判断是函数还是方法?
看他的调用者是谁,如果是类,就需要传入一个参数self的值,这时他就是一个函数,
如果调用者是对象,就不需要给self传入参数值,这时他就是一个方法
print(isinstance(obj.func, FunctionType)) # False
print(isinstance(obj.func, MethodType)) # True
64:静态方法和类方法区别?
尽管 classmethod 和 staticmethod 非常相似,但在用法上依然有一些明显的区别。classmethod 必须有一个指向类对象的引用作为第一个参数cls,而 staticmethod 可以没有任何参数。
举个栗子:
class Num:
# 普通方法:能用Num调用而不能用实例化对象调用
def one():
print('1')
# 实例方法:能用实例化对象调用而不能用Num调用
def two(self):
print('2')
# 静态方法:能用Num和实例化对象调用
@staticmethod
def three():
print('3')
# 类方法:第一个参数cls长什么样不重要,都是指Num类本身,调用时将Num类作为对象隐式地传入方法
@classmethod
def go(cls):
cls.three()
Num.one() #1
#Num.two() #TypeError: two() missing 1 required positional argument: 'self'
Num.three() #3
Num.go() #3
i=Num()
#i.one() #TypeError: one() takes 0 positional arguments but 1 was given
i.two() #2
i.three() #3
i.go() #3
65:列举面向对象中的特殊成员以及应用场景
__call__
__new__
__init__
__doc__
__class__
__del__
__dict__
__str__
66:1、2、3、4、5 能组成多少个互不相同且无重复的三位数
60个(A35)。
题意理解:组成后的数值不相同,且组合的三个位数之间数字不重复。
使用python内置的排列组合函数(不放回抽样排列)
product 笛卡尔积 (有放回抽样排列)
permutations 排列 (不放回抽样排列)
combinations 组合,没有重复 (不放回抽样组合)
combinations_with_replacement 组合,有重复 (有放回抽样组合)
import itertools
print(len(list(itertools.permutations('12345', 3)))) # 60
67:什么是反射?以及应⽤用场景?
反射的核心本质就是以字符串的形式去导入个模块,利用字符串的形式去执行函数。
Django中的CBV就是基于反射实现的。
68:metaclass作用?以及应用场景?
metaclass用来指定类是由谁创建的。
类的metaclass默认是type。我们也可以指定类的metaclass值。在python3中:
class MyType(type): # 传入type
def __call__(self, *args, **kwargs):
return 'MyType'
class Foo(object, metaclass=MyType):
def __init__(self):
return 'init'
def __new__(cls, *args, **kwargs):
return cls.__init__(cls)
def __call__(self, *args, **kwargs):
return 'call'
obj = Foo()
print(obj) # MyType
69:用尽量多的方法实现单例模式
1:使用模块
Python的模块就是天然的单例模式。
因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。
例如:
class Single(object):
def foo(self):
pass
single = Single() # 实例好一个对象
将上面代码保存在文件test.py,要使用时,直接在其他文件中导入此文件中的对象,这个对象就是单例模式的对象. 如:from test import single
2:使用装饰器
def single(cls):
_instance = {}
def _singlewrap(*args, **kwargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs)
return _instance[cls]
return _singlewrap
@single
class A(object):
def __init__(self, x=0):
self.x = x
a1 = A(1)
a2 = A(2)
print(a1 == a2) # True
3:基于__new__方法(推荐)
当我们实例化一个对象时,是先执行了类的__new__方法,我们没写时,默认调用object.new,实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式。
例:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'instance'):
cls.instance = super().__new__(cls)
return cls.instance
a = Person('p1',21)
b = Person('p2',22)
print(a == b, a.name == b.name)
#这里的打印结果都是True,可见 a 和 b 都是同一个实例(实例 b 覆盖了实例 a)。
#单例作用:
#第一、控制资源的使用,通过线程同步来控制资源的并发访问;
#第二、控制实例产生的数量,达到节约资源的目的;
#第三、作为通信媒介使用,也就是数据共享。比如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源。
#应用场景:
• Python的logger就是一个单例模式,用以日志记录
• 线程池、数据库连接池等资源池一般也用单例模式
• Windows的资源管理器是一个单例模式
• 网站计数器
70:装饰器器的写法以及应用场景
含义:装饰器本质就是函数,为其他函数添加附加功能。
原则:
不修改被修饰函数的代码;
不修改被修饰函数的调用方式。
应用场景:
无参装饰器在用户登录认证中常见
有参装饰器在flask的路由系统中见到过
import functools
def wrapper(func):
@functools.wraps(func)
def inner(*args, **kwargs):
print('我是装饰器')
return func
return inner
@wrapper
def index():
print('我是被装饰函数')
return None
#应用场景
- 高阶函数
- 闭包
71:异常处理写法以及如何主动抛出异常(应用场景)
#捕获异常
def temp_convert(var):
try:
return int(var)
except ValueError as Argument:
print ("参数没有包含数字%s"%Argument)
#调用函数
temp_convert("xyz")
#以10为基数的int()的无效文字:“xyz”
#raise语法
#raise [Exception(args [,traceback])]
#语句中Exception是异常的类型,args是自已提供的异常参数。
class Networkerror(RuntimeError):
def __init__(self, arg):
self.args = arg
try:
raise Networkerror("Bad hostname")
except Networkerror as e:
print(e.args)
72:什么是面向对象的mro
mro就是方法解析顺序,代表了类继承的顺序。经典类在多重继承时采用深度优先原则,而新式类是采用广度优先的原则。
73:isinstance作用以及应用场景?
isinstance(对象,类) 判断这个对象是不是这个类或者这个类的子类的实例。
#判断a 属不属于A这个类(可以判断到祖宗类)
class A:
pass
class B(A):
pass
a = A()
b = B()
print(isinstance(b,A)) # ===> True 判断到祖宗类
#任何与object都是True,内部都继承object
class A:pass
a = A() # 实例化
print(isinstance(a,object)) # True
应用场景:rest framework 认证的流程
scrapy-redis
74:写代码并实现
Given an array of integers, return indices of the two numbers such that they add up to a
specific target.You may assume that each input would have exactly one solution, and you may
not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]
75:json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?
支持几乎除了集合和日期之外的Python对象。
#json模块不支持datetime序列化,需要自定义格式类
class ComplexEncoder(json.JSONEncoder): # 继承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 super().default(self, obj) # 返回父类方法
print(json.dumps({'now': datetime.now()}, cls=ComplexEncoder))
76:json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
在 dumps 函数中添加参数 ensure_ascii=False 即可解决。
77:什么是断言?应用场景?
语法:assert ‘条件’, ‘提示’
其中,若"条件"为真,程序继续执行;若"条件"为假,程序终止,并给出"提示"。
用于程序的调试。
78:有用过with语句吗?它的好处是什么?
上下文管理器:在正常处理系统资源(文件、线程锁和连接)之前需要先执行一些准备动作,及其之后需要继续执行一些收尾动作。
例如:当需要操作文件或数据库的时候,首先需要获取文件句柄或者数据库连接对象,当执行完相应的操作后,需要执行释放文件句柄或者关闭数据库连接的动作。
又如,当多线程程序需要访问临界资源的时候,线程首先需要获取互斥锁,当执行完成并准备退出临界区的时候,需要释放互斥锁。
79:使用代码实现查看列举目录下的所有文件
os.listdir() ----列出当前目录和文件
os.walk() ----递归列出所有文件
80:简述 yield 和 yield from 关键字
yield 用于生成器;
yield from 用于协程。
更多推荐
所有评论(0)