python面试题汇总

2021/4/13 22:30:44

本文主要是介绍python面试题汇总,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

title: python面试题
date: 2021-04-07 20:12:03
tags:
top: 6

持续更新中…

  1. python的特点

     python是一种解释性语言
    
     python是交互式语言
    
     python是面向对象的语言
    
     python易于学习,易于阅读
    
     python可跨平台运行
    

2.Python优缺点

优点:

	易于学习、易于维护、易于阅读

	一个广泛的标准库

	支持交互,在终端敲命令的形式得到运行的结果

	可移植性

	可扩展性【可以调用C或C++写的代码】

	数据库【python提供所有商业数据接口】

	GUI编程(图形化界面)

	可嵌入式

缺点:

	运行速度相比C非常慢

	代码不能加密

3.python应用场景

web开发【通过mod_wsgi模块,Apache可以运行用Python编写的Web程序。Python定义了WSGI标准应用接口来协调Http服务器与基于Python的Web程序之间的通信。一些Web框架,如Django,TurboGears,web2py,Zope等,可以让程序员轻松地开发和管理复杂的Web程序】

操作系统管理、服务器运维的自动化脚本【在很多操作系统里,Python是标准的系统组件。 大多数Linux发行版以及NetBSD、OpenBSD和Mac OS X都集成了Python,可以在终端下直接运行Python。Python编写的系统管理脚本在可读性、性能、代码重用度、扩展性几方面都优于普通的shell脚本】

网络爬虫【Python有大量的HTTP请求处理库和HTML解析库,并且有成熟高效的爬虫框架Scrapy和分布式解决方案scrapy-redis,在爬虫的应用方面非常广泛】

科学计算(数据分析)【NumPy、SciPy、Pandas、Matplotlib可以让Python程序员编写科学计算程序】

桌面软件【PyQt、PySide、wxPython、PyGTK是Python快速开发桌面应用程序的利器】

服务器软件【Python对于各种网络协议的支持很完善,因此经常被用于编写服务器软件、网络爬虫。第三方库Twisted支持异步网络编程和多数标准的网络协议(包含客户端和服务器),并且提供了多种工具,被广泛用于编写高性能的服务器软件】

游戏【很多游戏使用C++编写图形显示等高性能模块,而使用Python或者Lua编写游戏的逻辑、服务器。相较于Python,Lua的功能更简单、体积更小;而Python则支持更多的特性和数据类型】

4.交换两个变量的值

a.设置新变量当中转空间

a = 10
b = 20
temp = 0
temp = a
a = b
b = temp

b.加减法

a = 10
b = 20
a = a + b  # a = 10 + 20
b = a - b  # b = 30 - 20
a = a - b  # a = 30 - 10

c.python专有的交换方式

a = 10
b = 20
a, b = b, a

d.异或,计算机二进制运算按位异或

一个数异或一个数两次,这个数不变

a = 10
b = 20
a = a ^ b        # a = a ^ b
b = a ^ b ^ b    # b = a
a = a ^ b        # a = a(a ^ b) ^ a

5.Python中的内存管理机制

定义变量的机制:定义一个变量相当于在计算机内存中开辟了一块空间,用于存储指定的数据。

变量的本质:变量实际上存储的是数据的地址。

计算机的内存:

	栈:引用【变量名】

	堆:实际的数据【对象】

6.进制问题

print(int("0b1102", base=16))

分析:进制问题,注意2进制只能由1和0组成,8进制的范围是07,16进制的范围是09 + a~f

虽然是0b开头,但是中间出现了2,那么这个数是能是16进制。

7.python2.x和python3.x的版本的区别

print 函数

	Python3.x当中打印方式为print()函数

print("HelloWorld")

	Python2.x当中打印方式为prin语句

print "HelloWorld"

	Python2.6和Python2.7为二者的过渡版本,上面两种方法都支持。

Unicode 编码表

Python 2.x 有 ASCII str() 类型,unicode() 是单独的,不是 byte 类型。

Python3.x有了Unicode(utf-8)字符串,以及一个字节类:byte和bytearrays。

中国 = 123

Python3.x支持上面这个写法,Python2.x不支持

除法

” / “

Python2.x当中,整型数字之间相除,产生的结果会舍去小数部分,结果也为整型。

Python3.x当中,整型数字之间相除,产生的是一个浮点数。

” // “整除

Python2.x和Python3.x运算规则一样。

异常

捕获异常的语法由 except exc, var 改为 except exc as var

使用语法except (exc1, exc2) as var可以同时捕获多种类别的异常

在2.x时代,所有类型的对象都是可以被直接抛出的,在3.x时代,只有继承自BaseException的对象才可以被抛出。

2.x raise语句使用逗号将抛出对象类型和参数分开,3.x取消了这种奇葩的写法,直接调用构造函数抛出对象即可。

在2.x时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情,在3.x中可以看出,设计者让异常变的更加专一,只有在错误发生的情况才能去用异常捕获语句来处理。

xrange

在 Python 2 中 xrange() 创建迭代对象的用法是非常流行的。比如: for 循环或者是列表/集合/字典推导式。

这个表现十分像生成器(比如。“惰性求值”)。但是这个 xrange-iterable 是无穷的,意味着你可以无限遍历。

由于它的惰性求值,如果你不得仅仅不遍历它一次,xrange() 函数 比 range() 更快(比如 for 循环)。尽管如此,对比迭代一次,不建议你重复迭代多次,因为生成器每次都从头开始。

在 Python 3 中,range() 是像 xrange() 那样实现以至于一个专门的 xrange() 函数都不再存在(在 Python 3 中 xrange() 会抛出命名异常)。

八进制字面量表示

八进制数必须写成0o777,原来的形式0777不能用了;二进制必须写成0b111。

新增了一个bin()函数用于将一个整数转换成二进制字串。 Python 2.6已经支持这两种语法。

在Python 3.x中,表示八进制字面量的方式只有一种,就是0o1000。

不等运算符

Python 2.x中不等于有两种写法 != 和 <>

Python 3.x中去掉了<>, 只有!=一种写法

去掉repr表达式"

Python 2.x 中反引号``相当于repr函数的作用

Python 3.x 中去掉了``这种写法,只允许使用repr函数

数据类型

Python3.x中去掉了Python2.x当中的long数据类型,新增了bytes类型

str 对象和 bytes 对象可以使用 .encode() (str -> bytes) 或 .decode() (bytes -> str)方法相互转化

8.简述if语句中的单分支、双分支和多分支的区别

单分支:

判断条件是否成立,成立执行if所属下面的语句,不成立不执行。

双分支:

if—else语句:条件成立执行if所属下面的语句,不成立执行else所属下面的语句。

多分枝:

if-elif…else语句,实现多选一,从上往下依次判断,只要有一个条件成立,那只执行对应的分支语句,执行完毕,整个if语句结束,所有条件不成立,执行else当中的语句。

9.break和continue的区别

break:

	作用:跳出整个循环体【结束循环,执行循环后面的语句】

	注意:break讲究就近原则,跳出距离最近的循环

continue:

	作用:跳过当前正在执行的循环,然后进行下一轮循环【结束本次循环,执行下一次循环】

10.is 和 == 的区别

is 是比较两个变量的【对象】的地址

== 是比较两个变量【对象】的内容

如果两个变量的地址相同,则这两个变量的内容一定相同

如果两个变量的内容相同,则这两个变量的地址不一定相同

11.短路原则

1.A and B,如果A为False,不需要计算B的值,整个表达式结果为False

2.A or B,如果A为True,不需要计算B的值,整个个表达式结果为True

3.and 和 or 混合使用

a.表达式从左往右运算,如果or的左侧为True,则会短路or后所有的表达式【不管后面连接了and还是or】

b.表达式从左往右运算,如果and的左侧为False,则短路后面所有的and,直到or出现,接着计算。

c.如果or的左侧为False,或者and的左侧为True,则不能使用短路逻辑判断

注意:被短路的表达式都不会执行

12.身份运算符

身份运算符用于比较两个对象的存储单元【地址】

is:判断两个标识符是不是引用自一个对象

is not:判断两个标识符是不是引用自不同对象

13.什么是列表切片?请举例说明

通过指定的区间和指定的步长,获取指定列表中的指定元素,生成一个新的列表。

切片之后的结果要么非空,要么为空,不会报错

list1 = [1, 2, 3, 4, 5]
list2 = list1[1:3:]
list2 = [2, 3]

print(list1[100:])  # []
print(list1[0:-1])  # 等价于[0:4]  [1,2,3,4]
print(list1[5:100]) # []
print(list1[::1])   # 顺序
print(list1[::-1])  # 倒叙
print(list1[-1:0])) # 相当于list1[-1:-5:1]   []
print(list1[-1:0:-1]) # 相当于list1[-1:-5:-1]  [5,4,3,2]

14.列表操作中,append和extend的区别和联系

相同点:

	1.都是向列表添加元素,并且都是添加在末尾。

	2.二者一次只能传递一个数据

	3.二者都是在原列表的基础上添加元素的,所以返回值都为None

不同点:

	1.append可以向列表添加任何类型的元素,extend只能向列表添加可迭代对象。

	2.append添加序列的时候会把整个序列当作一个元素添加到列表里面,extend会把序列里面的元素一个个依次添加到列表类面。

15.代码阅读

a = [1, 2, 3]
b = [4, 5]
c = [a, b]
d = c
e = c.copy()
a.append(20)
print(c,d,e)

# 最开始c = [[1, 2, 3], [4,5]]  d = [[1, 2, 3], [4,5]]
# e =  = [[1, 2, 3], [4,5]]
# d属于直接引用
# e属于浅拷贝
# a.append(20) ————》 a = [1, 2, 3, 20] 在a的末尾添加元素20
# 由于都不是深拷贝,所以内层元素发生改变,其他列表也会随着发生改变
c = [[1, 2, 3, 20], [4,5]]
d = [[1, 2, 3, 20], [4,5]]
e = [[1, 2, 3, 20], [4,5]]

16.代码阅读

a = [1, 2, ['a', 'b']]
b = a 
c = copy.deepcopy(a)
a[-1].append(3)
print(b)
print(c)

解析:

# b是直接引用a
# c是深拷贝a
# 所以,a内部元素变化会对b 造成影响,但不会对c造成影响
b = [1, 2, ['a', 'b', 3]]
c = [1, 2, ['a', 'b']]

17.代码阅读

a = [1, 2, ['a', 'b']]
b = a
c = copy.deepcopy(a)
a.append(3)
print(b)
print(c)

解析:

"""
c是深拷贝a
b是直接引用
a.append(3)改变了a 的外层元素,
对深拷贝没有影响,但对于直接引用有直接的影响
"""
b = [1, 2, ['a', 'b',], 3]
c = [1, 2, ['a', 'b']]

18.引用赋值、浅拷贝、深拷贝

引用赋值:不管是几维列表,一个列表的元素改变,另一个随着改变

列表.copy()和copy.copy():

	对于一维列表,一个列表的元素改变,另一个不会改变

	对于二维列表,一个列表的元素改变另一个会随着改变

对copy.deepcopy():不管是几维列表,一个列表的元素改变,另一个都不会改变。

19.可变数据类型和不可变数据类型的区别

不可变数据类型:int, float, bool, str, tuple,通过变量赋值的方式操作,一个变量的值发生改变,另一个变量不受影响。

可变数据类型:list, dict, set,通过变量赋值的操作,一个变量内部的元素改变,另一个变量会随着改变。

20.元组和列表的区别和联系

相同点:

	1.二者都是有序的

	2.二者都可以存储不同类型的元素

	3.二者都可以存储重复元素

	4.二者的遍历方式完全相同

不同点:

	1.表示方式:元组::(),列表:[]

	2.可变性:元组是不可变,列表是可变的

	3.使用场景:在多线程的使用场景中,为了避免多线程访问同一个数据造成的混乱,则可以使用元组。如果涉及到元素的增加或者删除,则可以使用列表。

	4.元组在创建时间和占用空间都优于列表。

21.创建字典的五种方式

方式一:创建并传入键值对

dict1 = {"aa": 10, "bb": 20}
print(dict1)

方式二:先创建,再传入键值对

dict2 = {}
dict2["aa"] = 10
dict2["bb"] = 20
print(diict2)

方式三:dict3 = dict(key = value, …)

dict3 = dict(name = "xiaokeai", age = 10)
print(dict3)

方式四:dict([(key1,value1), (key2, value2)])

dict4 = ([("a",11), ("b",22),("c",33)])
print(dict4)

方式五:dict(zip[所有的key], [所有的value])

dict5 = {zip[11,22,33],["a","b","c"]}
print(dict5)

22.字典的update()方法

update():更新,合并字典,将指定字典中的键值对添加到原字典中

23.区分字典zip方法和dict.fromkeys创建字典的区别

 dict1 = dict(zip([11,22],["a","b"]))
 print(dict1) # {11:"a", 22:"b"}

 dict2 = dict.fromkeys([11,22],["a", "b"])
 print(dict2) # {11:["a", "b"], 22:["a", "b"]}

24.add 和uptate之间的区别和联系

相同点:

	1.都是向集合中添加元素

	2.都只能识别一个元素

不同点:

	1.add只能添加不可变的数据类型

	2.update只能添加可迭代对象【list,str,tuple,dict】

	3.如果添加的数据为元组,add会将整个元组当作元素添加到集合当中,update只会将元组里面的元素添加到集合当中。

25.集合间的运算

1.交集 &

set1 = {1,2,3} set2 = {3,4,5} # 算术运算符 set3 = ste1 & set2 # 系统功能 set4 = set1.intersection(set2)

2.并集 |

set1 = {1,2,3} set2 = {3,4,5} # 算术运算符 set3 = ste1 | set2 # 系统功能 set4 = set1.union(set2)

3.差集 -

set1 = {1,2,3} set2 = {3,4,5} # 算术运算符 set3 = ste1 - set2 # 系统功能 set4 = set1.differance(set2)

4.差集的并集/并集 - 交集

set1 = {1,2,3} set2 = {3,4,5} # 算术运算符 set3 = ste1 ^ set2

26.阅读下面代码,输出结果

def test(num1,num2,*num3,num4):
    print(num1,num2,num3,num4)

test(6,4,5,65,566,88,89,88)

分析:结果会报错,不定长参数出现在形参列表的中间,在传递实参的时候,在可变长参数后面的参数不是关键字参数,会导致可变长参数接收num2以后的所有数据,结果导致num4接收不到参数而报错。

注意:在形参列表中,不定长参数最好出现在形参列表的最后,如果出现在形参列表的中间位置,则可以在实参列表中借助于关键字参数解除歧义。

27.简述值传递和引用传递的作用

值传递:实参是不可变数据类型

引用传递:实参是可变的数据类型

28.阅读下面的代码,写出执行结果

def func():
    a = []
    for i in range(5):
        a.append(lambda x:i * x)
        
    return a
result = func()
print(result[0](2))
print(result[1](2))
print(result[2](2))
print(result[3](2))
print(result[4](2))

分析:result = func()调用函数func()产生了五个匿名函数,并且存放到列表a当中,后面的五句代码是在调用存在列表a当中的五个匿名函数,由于第一次调用func()的时候i已经变成了4,所以五个函数中的i都是4,则结果为:8, 8, 8, 8, 8

29.什么是匿名函数,优缺点

是一个lambda表达式,本质上还是一个函数,可以设置参数,也可以进行调用,表达式本身就是函数运算的结果

优点:简化代码、减少内存空间的使用

缺点:只能实现简单的逻辑,逻辑一旦复杂,代码的可读性会降低,则不建议使用

30.全局变量的使用场景

问题:当全局变量和局部变量重名,在函数内部对变量直接进行运算,因为系统不能识别是对那个变量进行运算,所以报错

解决:使用global对变量进行声明,表示参与运算的变量来自全局

a = 28
def func():
    global a
    a += 1
func()
print(a)

31.简述可迭代对象和迭代器之间的区别和联系

区别:

	可迭代对象:Interable,可以直接作用于for循环,如:list,tuple,tr,dict,set,生成器等

	迭代器:Iterator,可以直接作用于for循环和next的数据,如:生成器

联系:

	迭代器一定是可迭代对象,可迭代对象不一定是迭代器但是,可以通过iter()将不是迭代器的可迭代对象转换位迭代器

32.代码阅读题

def func(li[]):
    li.append("abc")
    return li
print(func())  
# 调用func()函数,会往默认列表li里面添加"abc"  结果为["abc"]

print(func([3])) 
# func([3]),表示传入新的列表,列表里面已经有元素3, 所以结果为[3, "abc"]

print(func()) 
# 再次调用func()函数,会在之前调用之后li列表的基础上,
# 再次添加"abc"  结果为:["abc", "abc"]

print(func([3])) 
# 传入新的列表,注意:虽然里面元素跟前面一样,但这是两个不同的列表。
# 所以结果为[3,"abc"]

33.需求:书写一个装饰器,可以统计任意一个函数的执行时间

import time
def get_time(func):
    inner(*args,**kwargs):
        # 开始时间
        start_time = time.time()
        func(*args,**kwargs)
        # 结束时间
        end_time = time.time()
        return round(end_time - start_time, 3)
    # 返回内部函数的引用
    return inner
@get_time
def test():
    for _ in range(10**8):
        pass
    return 100

34.斐波那契数列(递归)

def func(n):
    if n == 1 or n == 2:
        return 1 
    else:
        return func(n-1) + func(n-2)

35.简述变量的作用域有哪些,全局变量和局部变量有什么区别

变量作用域分类:

	全局作用域:Global

	函数作用域:Enclosing

	局部作用域:ocal

	内置作用域:Built-in

全局变量:定义在函数的外部的变量,可以在整个程序中被访问

局部变量:定义在函数内部的变量,仅限于在该函数的内部被访问

36.简述类属性和实例属性的区别和联系/简述类的字段和对象的字段的区别和联系

1.定义的位置不同:类属性直接定义在类中,实例属性:动态绑定或者定义在构造函数中

2.访问方式不同:类属性可以通过对象或者类名访问,实例属性只能通过对象访问

3.在内存中出现的实际不同:类属性随着类的加载而出现,实例属性随着对象的创建而出现

4.优先级不同:当类属性和实例属性重名的时候,使用对象优先访问实例属性

5.使用场景不同:如果是多个对象共享的数据则定义位类属性,如果是对象特有的数据,则定义位实例属性。

37.new和init的工作原理

1.当代码执行变量 = 类名() 语法是,可以创建一个对象出来,主要是因为先调用了new,然后调用了init

2.创建对象的时候会自动调用new,该函数的返回值就是被当前创建的对象【实例】

3.当对象创建完毕之后,会自动调用init,在该函数内部给对象赋初始值

4.不管是new还是init是否显式的书写在类中,永远都是先调用new,然后再调用init

5.首先将指定类传参给new,创建一个对象并返回,然后将该对象传参给init,则可以给对象设置初始值

38.构造函数init和普通函数的区别

不同点:

1.函数名不同:实力函数的函数名可以自定义,init的函数名是固定的

2.调用不同:init是在创建对象的过程中被自动调用的,而实例函数必须手动调用

3.调用次数:对于同一个对象而言,init一般只会被调用一次,而实例函数可以根据需求调用多次

相同点:

1.二者都定义在类中,形参列表的第一个参数都是self,二者都可以被称为实例函数。

2.形参列表可以设置为默认参数,不定长参数,实参列表也可以使用关键字参数

3.二者都可以根据需求设置返回值

39.面向对象的特征是什么,怎么使用,有什么作用?

封装:

a.将不希望被外界直接访问的属性进行私有化,在定义属性的时候在属性名前家两个下划线

作用:为了提高数据的安全性,为了提高数据的复用性

b.封装式定义类的准则【根据各个对象的特点,将相同的属性和行为提取出来一个新的类,还可以进行属性私有化】

继承:

a.将多个相似类中的属性和函数提取出来,形成一个父类,子类将会继承父类中未被私有化的属性和函数

作用:简化代码,提高了代码的复用性,提高了代码的可扩展性

b.继承是设计类的技巧【父类和子类,为了代码的复用性】

多态:

a.在继承的前提下,当代码运行的时候,根据传入的对象确定该对象是什么类型,可以调用哪个函数

作用:增加代码的灵活性

b.多态式调用函数的技巧【不同的子类可以调用不同的函数,产生不同的结果】

40.代码阅读题

@property装饰器装饰类函数,表示将函数转换为属性使用

阅读下面代码,写出执行结果

class Person(boject):
    @property
    def show(self):
        print("show")
p = Person()
print(p.show)

分析:p.show表示对象p调用函数show,控制台会打印show,然后print(p.show)表示打印show函数的返回值,而show函数返回值为None所以打印结果为:

show

None

41.解释下面不同书写形式的属性的含义

a:普通属性/公开属性,在类的内外可以直接访问

_a:一般称为保护属性,在类的内外都可以直接访问,但是,一般不建议使用

__a:私有属性,只能在类的内部被访问,在类的外面一般借助于暴露的函数

a:自定义的变量不建议使用 ,一般体现为系统属性或者系统函数的用法,如:init、new、str、repr

42.继承的特点和优点

继承的特点:

1.子类对象可以直接访问父类中为被私有化的属性

2.子类对象可以直接调用父类中为被私有化的函数

3.父类对象不能访问子类中特有的属性和函数

继承的优点:

1.可以简化代码

2.提高了代码的可复用性

3.提高了代码的可扩展性

4。继承是多态的前提

43.类属性

class Mclass1(object):
    x = 10
class Myclass2(Mclass1):
    pass
class Myclass3(Myclass1):
    pass

print(Myclass1.x,Myclass2.x,Myclass3.x)
Myclass2.x = 20
print(Myclass1.x,Myclass2.x,Myclass3.x)
Mclass1.x = 30
print(Myclass1.x,Myclass2.x,Myclass3.x)

分析:

第一次打印:都继承自父类Myclass1的属性,打印结果为:10 10 10

第二次打印:Myclass2修改了属性的指向,Myclass3还是继承自父类Myclass1的属性,打印结果为:10 20 10

打三次打印:父类修改类指向,Myclass2指向是属于自己定义的指向,不会继承父类的属性,所以打印结果为:30 20 30

44.继承树/菱形冲突

结论:

在多继承中,如果多个类之间的继承关系比较复杂,则被称为继承树或者菱形冲突

在多继承中,如果在中间某层有向上解析的迹象,则按照父类列表中弗雷德排序顺序进行广度排序

45.简述实例函数、类函数、静态函数之间的区别和联系

相同点:

本质上都是函数,所以默认参数,关键字参数,不定长参数都可以正常使用,也可以设置返回值

不同点:

1.是否有装饰器:类函数需要@classmethod装饰器修饰,静态函数需要staticmethod装饰器修饰,实例函数不需要装饰器修饰。

2.参数列表不同:类函数第一个参数必须为cls,实例函数第一个参数必须为self,静态函数对参数列表没有要求

3.调用方式不同:类函数和静态函数都可以使用类名或者对象调用,但实例函数只能通过实例对象调用

4.使用场景不同:

			a.如需要在函数内部创建当前类的对象,则选择类函数

			b.如果需要封装一个工具类,为了简化函数的调用,建议使用类函数或者静态函数

			c.如需要在函数内部获取对象的属性,则选择实例函数

46.统计创建对象的个数

方式一:new

class Person(object):
    __per_count = 0
    def __new__(cls,*args**kwargs):
        print("new方法被调用了")
        cls.__per_count += 1
        return object.__new__(cls)
    def __init__(self):
        print("init被调用了")
    @classmethod
    def get_count():
        return cls.__per_count

方式二:init

class Person(object):
    __per_count = 0
    @classmethod
    def __init__(cls):
        print("hello",cls)
        cls.__per_count += 1
    @classmethod
    def get_count(cls):
        return cls.__per_count

47.什么是单例设计模式?

定义一个普通类,该类可以创建无数个对象,定义一个类,让该类只能创建一个对象,该类被称为单例类,单例:单个实例【对象】

程序运行过程中,确保某一个类只有一个实例【对象】,不管在哪个模块去这个类的对象,获取到的都是同一个对象。该类有一个静态方法,像整个工程提供这个实例,例如:一个国家只有一个主席

单例设计模式的核心:一个类有且只有一个实例,并且这个实例需要应用于整个程序中,该类被称为单例类

48.两种实现方式单例设计模式

类属性实现单例设计模式

"""
设计模式
    经过总结,优化,对我们经常遇到的问题所提出的一些可重用的方案
    设计模式是一种必须在特定的情境下使用的一种解决问题的犯案,不绑定编程语言
    23种设计模式,常用的单例,MVC(MTV),生产者消费者设计模式

单例设计模式:
    单例:单个实例,单个对象
    程序在运行过程中,确保一个类只能创建一个实例,不管在当前程序中哪个模块中获取该类对象,获取到的都是同一个对象
单例设计模式的核心:一个类仅有一个实例,该实例还需被应用在整个程序中
"""


class Person(object):
    __instance = None

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = super(Person, cls).__new__(cls)
        return cls.__instance


class A(object):
    """
    每次创建对象,都会调用__new__和__init__,只有第一次调用时__init__是动态绑定属性,
    后面调用都是对属性的重新赋值

    """
    __isinstance = None

    def __new__(cls, *args, **kwargs):
        if cls.__isinstance is None:
            cls.__isinstance = super(A, cls).__new__(cls)
        return cls.__isinstance

    def __init__(self, name, age):
        self.name = name
        self.age = age


a1 = A('jack', 12)
a2 = A('tom', 13)
print(id(a1))
print(id(a2))

装饰器实现单例设计模式

# 1.装饰器装饰类
def singleton(cls):
    instance = None

    def getinstance(*args, **kwargs):
        nonlocal instance
        # 构造函数只会在第一次创建对象的时候被调用
        if instance is None:
            instance = cls(*args, **kwargs)
        return instance

    return getinstance


@singleton
class A(object):
    pass


a1 = A()
a2 = A()
print(id(a1))
print(id(a2))

49.异常

当函数中使用了try_except_finally语句,如果在try或者except中使用return语句,finally不受影响,仍然会执行

def test(): 
    try:
        num = = int(input("请输入一个数字:"))
        list1 = [2,2,3]
        print(list1[num])
        return
    except ValueErroy as e:
        print(e)
    except IndexErroy as e:
        print(e)
    finally:
        print("finally执行了")

50.with 上下文件管理异常工作原理

class Check(object):
    def __enter__(self):
        # 当对象进入上下文件管理时,主要是为了初始化相应的资源,如,打开文件
        print("enter")
        return self
    def __exit__(self,exc_type,exc_val,exc_tb):
        print("exit")
        # exc_type异常类型,exc_val异常值
        # 如果出现异常,系统内部会自己处理,不会向Python解释器抛出异常
        return True
with Check() as c:
    print(c)

51.闭包

当一个嵌套函数在其外部区域引用了一个值时,该嵌套函数就是一个闭包,以下代码输出值为:

链接:https://www.nowcoder.com/questionTerminal/d173f0f517de45cb88eff23f8901f2d1?toCommentId=8049851
来源:牛客网

def adder(x):
    def wrapper(y):
        return x + y
    return wrapper
adder5 = adder(5)
print(adder5(adder5(6)))
  • A.10
  • B.12
  • C.14
  • D.16

解析:

1.得出adder5的结果:

adder5 = adder(5) —> x=5, 并返回wrapper的引用

2.由adder5得出adder5(adder5(6))的结果:

adder5(adder5(6))

----->x=5,wrapper(x=5,wrapper(6))

----->x=5,wrapper(11)

----->5 + 11 = 16



这篇关于python面试题汇总的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程