首页 > 其他分享 >面试题1

面试题1

时间:2022-09-26 09:00:20浏览次数:42  
标签:__ 面试题 next lst func print def

# 第一题(列举了解的编程语言及语言的区别)
编译型语言:一次性 把代码都编译成二进制,然后运行
解释型语言:实时性 一行一行,编译一句,运行一句
1.python 解释型 简洁高效,容易上手
2.java 混合型(JVM,JIT编译器),开发周期慢,突出在web方向
3.c 编译型 属于计算机底层语言,只有面向过程,没有面向对象
4.c++ 编译型 属于计算机底层语言,既有面向过程,也有面向对象
5.go 编译型 应用在区块链,高并发高可用,也可以突出在游戏领域

# 第二题
# python2.x
1.print "123"
2.range 返回列表
3.默认编码 -- ascii
4.两种类: 经典类 和 新式类 (两种类都存在 通过括号里是否有object判断)
class Car():pass 经典类(多继承当中的搜索原则采用深度优先)
class Car(object):pass 新式类(多继承当中的搜索原则采用广度优先)
5.除法/: 结果是整型
6.int(整型4) 默认四个字节 long(长整型8) 默认八个字节
7.raw_input <=> python3.x input (写法上不一样)


# python3.x
1.print("12")
2.range 返回的是 可迭代对象(可循环的数据)
3.默认编码 utf-8
4.都是新式类(广度优先) (有个个方法可以查看继承的调用 关系顺序) 类.mro() => 继承关系列表
5.除法/: 结果是小数
6.int (去掉long 也没有字节限定要求)
7.input

# 第三题
# 逻辑运算符优先级 () > not > and > or
逻辑短路
True or print(111) # 不会被打印出来 短路了 or后面就不执行了
False and print(222) # 短路了 and后面就不执行了

and 逻辑与 全真则真 一假则假
or 逻辑或 全假则假 一真则真

布尔值为假的十种情况:
0 0.0 False 0j(复数) '' () [] set() {} None

复数: 实数 + 虚数
"""
复数: 3 + 4j
实数: 3 虚数: 4j
如果有一个数,他的平方等于-1,那么这个数就是j
科学家认为有,表达高精度类型;
"""

v1 = 1 or 2
print(v1) # 短路了 1

v2 = 3 and 7 or 9 and 0
# v2 = 7 or 0 # 先算and
print(v2)


# 第四题
"""逗号是区分是否是元组的标识符"""
v1 = [1,2,3]
v2 = [(1),(2),(3)] # v1和v2一样 (1)整整型
v3 = [(1,),(2,),(3,)]
# v1 列表 v2 列表 v3里面的元素是元组

# 第五题 (用一行代码实现数值交换)
a = 1
b = 2
# 方法一 python特有
a,b = b,a
# 方法二
tmp = a
a = b
b = tmp

# 第六题
单双引号没有任何区别,三引号可以支持跨行 (注释就是字符串 可以赋值给变量)
注意的是 在引号互相嵌套时,里面不能使用相同的引号
str = """
asdfasfdasf
"""

# 第七题
is 是判断内存地址是否相同
== 判断两边的值是否相同

# 小数据池,也称为小整数缓存机制,或者称为驻留机制 (大前提:小数据池,只针对,整数,字符串,bool值。)
# Python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,
# 而是使用已经创建好的缓存对象 只开辟了一个空间

# 在内存中开辟了一个空间 内存地址一样
v1 = 10
v2 = 10

# 针对于整型 在-5 ~ 正无穷 如果两个值相同 就会有相同的地址 开辟一个空间 [python3.6之前有效]
# 开辟了两个空间 内存地址不一样
var1 = -100
var2 = -100
print(var1 is var2) # False


# 第八题 tuple(数据)和list(数据)转换
# int float complex bool str list tuple set dict
tuple(数据) list(数据)

# 字典的键 和 集合的值 有数据类型上的要求 (可哈希的)
Number ( int float complex bool) str tuple (可哈希 不可变的数据类型)

# 强转成字典,对数据类型的要求是?
# 必须是等长的二级容器,并且元素个数是2个
print( dict([("a",1),["b",2]]) )
# {"a":1,"b":2}
""" 里面容器的元素个数都相同 是等长 """
# 二级容器元素个数相同 三级容器必须当作值也可以强转
dict([ ("a",[1,2,3]) , ["b" , 456] ])
dic = {"a":[1,2,3],"b":456}

为什么底层用哈希算法
不用哈希的话: 要是无序散乱分配 分配不均匀 可能会把数据集中的分配到某一块内存区域 内存的使用效率不高
哈希算法:首先是无序的,目的是把数据相对均匀的存储在内存当中(数据分配均匀)(会把内存分成好多小份 相对均匀的往里分配) 底层用的是取模(取余)算法

可哈希:能够用哈希算法算的数据(不可变的Number ( int float complex bool) str tuple)才能勾存到内存
不可哈希:哈希算法不能够算的数据 没法存到内存 (也就是哪些可变的数据类型)

不可哈希没法用哈希算法存,比如列表 随便找一个区域塞进内存 有序的存储(有次序的就不能哈希)

# 第九题 字符串反转
name[::-1]

# 第十题 两个set如何获取交集、并集、差集
交集 &
集合.intersection(集合2)

差集 - 差集是一种集合运算,记A,B是两个集合,则所有属于A且不属于B的元素构成的集合,叫做集合A减集合B
difference

并集 |
union

对称差集 ^ (你的不同和我的不同的部分组成的集合)
symmetric_difference

# 第十一题 哪些情况 y!=x-(x-y)会成立
"""非空集合 且不为子父关系 的两个集合"""

"""
第一步 判定是集合
第二步 找成立的条件 不能是子父关系(你有的我全有 我有的你不一定有 爸包含儿子)

两个集合x y (减法只有集合能干 字符串可以加法)
x = {1,2,5}
y = {2,8}
y != x - (x-y) # x-y 就是差集

{2,8} != {1,2,5} - {1,5}
{2,8} != {2} # 成立 true
"""

# 第十二题 python中如何拷贝一个对象
# 浅拷贝 (三种)
# 1
# import copy
# 2
# lst = [1,2,3].copy()
# 3 切片
# lst[:] 或者 lst[::]

lst = [1,2,3]
lst2 = lst[:]
lst.append(4)
print(lst,lst2) # [1,2,3,4] [1,2,3]

# 深拷贝 (只有一种方式)
import copy
copy.deepcopy()


# 第十三题
# 赋值 : 将变量和值在内存中形成映射指向关系 (没有单独开辟空间 还是指向原有地址)

# 浅拷贝: 只拷贝容器第一层级里的所有元素,单独开辟空间成型独立的一份副本新的地址,二级容器不会开配新的空间还是用原来的地址 copy.copy() [1,2,34,5,[3,4,5]] [3,4,5]二级容器
from copy import copy
copy() # 也可以用一个copy 写法写法上的差别

# 深拷贝: 所有层级的元素都单独拷贝一份,开辟全新的空间
"""
(深拷贝 注意地址:原不可变数据只是暂时(如果改变了 还是得新开辟空间)的指向原数据,可变的数据(列表 字典 集合)会独立开辟新空间)
"""
"""
import copy
lst1 = [1,2,3,[4,5,6]] # 两级容器
lst2 = copy.deepcopy(lst1)
print(list2) # [1,2,3,[4,5,6]] 两个列表地址是一样的

lst2[0] = 100 # 把0位置的数据改一下
print(lst1,lst2)
print( id(lst1[0]) , id(lst2[0]) ) # 这个虽然是不可变类型 但是数据有变化所以这个位置的地址也会变
print( id(lst1[-1]) , id(lst2[-1]) ) # 列表 这个是可变数据 是不一样的地址
"""

# 第十四题 pass的作用
# 占位

# 第十五题
import copy
a = [1,2,4,5,['b','c']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('d')
# a,b 百分百一样
print(b) #[1,2,4,5,['b','c',"d"],5]
print(c) #[1,2,4,5,['b','c',"d"]]
print(a) #[1,2,4,5,['b','c',"d"],5]

# 第十六题
# 9成9乘法表
# while 写法
i = 1
while i<=9:
# 打印表达式
j = 1
while j<=i:
# "%d*%d=%2d "2d和 空行 是为了对齐
# print默认是打印一行,结尾加换行。end=' '意思是末尾不换行,加空格 表示这个语句还没结束
print("%d*%d=%2d " % (i,j,i*j) ,end="" )
j+=1
# 打印换行
print()
i+=1

# for 写法(有行有列 两个循环控制)
for i in range(1,10):
# 打印表达式 第几行就有几个表达式
for j in range(1,i+1):
print("%d*%d=%2d " % (j,i,i*j) ,end="" )

# 打印换行
print()

# 第十七题 斐波那契数列
# 1 1 2 3 5 8 13 21 34 .。。。
# 方法一
lst = [1,1]
for i in range(10):
lst.append(lst[-1] + lst[-2])
print(lst)

# 方法二
a,b = 0,1
for i in range(10):
print(b)
a,b = b,a+b

# 方法三 递归
def fib(n):
if n <= 2:
return 1
# n n-1 n-2
# 结果 = 上一个值 + 上上个值
return fib(n-1) + fib(n-2)
print(fib(5))


"""
递归经典案例
斐波那契数列
def fib(n):
if n <= 2:
return 1
# 结果 = 上一个值 + 上上个值
return fib(n-1) + fib(n-2)
print(fib(5))

1 1 2 3 5

# return 后面的值算完了才能通过return 进行返回
# 从底往上一层一层看
fib(5) => 5
return fib(4) => 3 + fib(3) => 2
fib(3) + fib(2) => 2 + 1 fib(2) + fib(1) => 1 + 1
fib(3) = fib(2) + fib(1) => 1 + 1 => 2

调用函数时候,每调用一次,都需要在内存当中开辟一个栈帧空间
递归就是不停的开辟空间和释放空间的过程
递: 去 (开辟空间)
归: 回 (释放空间)
一去一回是递归

触发递归 回 的过程有 两个条件:
(1) 最后一层 栈帧空间代码 全部执行完毕,触发回的过程,回到上一层空间的调用处;
(2) 最后一层 栈帧空间代码 遇到了return,触发回的过程,回到上一层空间的调用处;

"""

 


# 第十八题 去除列表中的重复值
list(set(lst))

# 第十九题 一个大小为100G的文件et_log.txt要读取文件中的内容写出具体过程代码
from collections import Iterator,Iterable
fp = open("文件",mode="r",encoding="utf-8") # 迭代器

# 方法一 fp 是迭代器 怕一行就是100G
for i in fp: # 遍历
print(i) # 按照文本中的行进行遍历.

# 方法二 如果方法一100G的文件都在一行上就不行了
with open("文件",mode="r",encoding="utf-8") as fp:
res = fp.read(100) # 先读100个字符
while res: # 判断是不是空
print(res)
res = fp.read(100)


# 第二十题
# zip 拉链 返回迭代器(对象 python里万物皆是对象)
it = zip( ("a","b") , [1,2] )
print(it) # <zip object at 0x00000000768c> 这是一个zip对象存在这个地址下
print(isinstance(it,Iterator)) # 是不是迭代器 返回True


dic = dict(zip( ("a","b") , [1,2] ))
print(dic) # {"a":1,"b":2}

a = dict(zip( ("a","b","c","d","e"),(1,2,3,4,5) ) )
print(a)

# enumerate 枚举 返回迭代器
it = enumerate( ["a","b"] )
list = list(it)
print(list)# [(0,"a"),(1,"b")]

it = enumerate( ["a","b"] , start=1) # start 指定枚举值 从哪开始
dic = dict(it)
print(dic) # {1:"a",2:"b"}

# 第二十一题 lambda关键字作用
lambda 匿名函数 : 用一句话来表达 只有返回值的 无名函数
lambda 参数 : 返回值

# 第二十二题 *arg **kwargs作用
# 定义处用( 收集参数)
# *arg 普通 收集参数 : 收集多余没人要的普通实参
# **kwargs 关键字 收集参数: 收集多余没人要的关键字实参

# 调用处用
# 聚合打散作用

# 第二十三题 函数中设置一个全局变量
def func():
global a
a = 90
func()
print(a)

# 第二十四题 filter map reduce 作用
# filter => 过滤数据
filter(函数,iterable) # 通过函数的True和Flase选择保留和舍弃

# 保留偶数 , 过滤掉所有的奇数
lst = [1,2,3,4,5]
it = filter(lambda x : True if x % 2 == 0 else False , lst)
print(list(it)) # [2,4]


# map -> 处理(映射)数据
map(func,iterable) => 迭代器 # 是每个数据都要处理没有过滤的问题

lst = [1,2,3]
it = map(lambda x : x * 3, lst)
print(list(it)) # [3,6,9]


# reduce -> 计算数据(一次性计算两个参数)
reduce(func,iterable) => 计算的结果 # 先从数据中拿出两个数

# 怎么把列表数据换成整型
from functools import reduce
lst = [5,4,8,8]
res = reduce(lambda x,y : x*10 + y , lst)
print(res,type(res)) # 5488 ,int
"""
# 经典案例
# 列表--》整型
[5,4,8,8] => 5488

5 * 10 + 4 = 54
54 * 10 + 8 = 548
548 * 10 + 8 = 5488
"""

# 第二十六题 python递归的最大层数

官方说法1000层 实际是994 ~ 1000 层

设置递归最大层数
import sys
sys.setrecursionlimit(99999999999999999)

# 第二十七题 什么是迭代器

dir(数据) => 查看该数据的内部成员
# 官方说法
具有 __iter__() 和 __next__() 两个方法的是迭代器
具有 __iter__() 可迭代对象

# 理解说法
迭代器: 迭代数据的 工具
可迭代对象:可以迭代的 数据

可迭代对象 =>(转变) 迭代器 (可迭代对象到迭代器的过程)
把不能够直接通过next获取的数据 =>(转变) 可以直接被next获取数据

 

# 第二十八题 什么是生成器
生成器的本质就是迭代器,可以自定义迭代的逻辑
创建方式两种
(1) 生成器表达式(推导式) a = (i for i in range(10)) # 返回的是生成器对象
(2) 生成器函数 (含有yield 关键字)


# 第二十九题 什么是装饰器
# 装饰器: 再不改变原有代码的情况下,为原函数扩展新功能
# 闭包:
# (1)互相嵌套的两个函数,内函数使用了外函数的局部变量
# (2)外函数把内函数返回 出来的过程,是闭包,内函数是闭包函数;

# 装饰器的本质就是闭包
# 应用:1、登录认证,2、框架(django, flask, 和路由分发:@app.route("/",method=["GET","POST"]))

 

# 第三十题 什么是反射及应用场景
# 通过 字符串 去操作 类对象或者模块当中的属性方法
# hasattr getattr() setattr() delattr()
# 应用:(不知道用户输入的什么 用户都输入的是字符串)可以配合用户的输入,进行动态操作,调用其中的成员 | 通过api接口调用


def func(x):
pass
func(x)
0 4 5 7 8 5 2


lst = [7,-8,5,4,0,-2 ,-5]
def func(x):
if x >= 0:
return x
else:
return abs(x)+x
res = sorted(lst,key=func)
print(res)

 

# 第三十一题 写一个普通的装饰器
"""
装饰器的本质是闭包
闭包特点:可以延长局部变量的生命周期
"""
def wrapper(func):
def inner(*args,**kwargs): # *args,**kwargs 收集那些没人要的垃圾参数
res = func(*args,**kwargs) # *args,**kwargs 参数的解包(聚合打散)
print("新添加一句话")
return res
return inner

@wrapper
def func():
print("心中存有一丝希望,终将带你走向光明 --正道的光")

func()
"""
@符 功能(装饰器执行流程)
1.先把装饰器修饰的函数当成参数传递给装饰器
2.将新函数返回,去替换旧函数 func = inner
"""


# 第三十二题 写一个带参数的装饰器
# 定义一个装饰器
def outer(n):
def wrapper(func):
def inner1(*args,**kwargs):
res = func(*args,**kwargs)
print("我是金角大王")
return res

def inner2(*args,**kwargs):
res = func(*args,**kwargs)
print("我是银角大王")
return res

if n == "alex":
return inner1
else:
return inner2
return wrapper

# 外函数outer中的参数n,存储了alex(闭包特点:可以延长局部变量的生命周期 等到函数全部执行完毕才会被释放)
# 先去执行outer("alex") => 返回 @wrapper => @发动技能
# @发动技能:
# 1.把func当成参数传递给wrapper
# 2.func = inner1

@outer("alex")
def func():
print("how are you ?")

func()


# 第三十三题 求结果
def num():
return [lambda x:i*x for i in range(4)]
# print([m(2) for m in num()])

# (1) 辨别 我到底是什么?
# 推导式 (正确)
[lambda x:i*x for i in range(4)]

# 匿名函数 (错的) 执行报错
func = lambda x : i*x for i in range(4)
# lambda表达式 (这种可以 必须得加[])
func = lambda x : [i*x for i in range(4)]
func(3)


# (2) 对原表达式进行拆解 (列表推导式)
def num():
# return [lambda x:i*x for i in range(4)] 此代码与下面代码等价
lst = []
for i in range(4): # 0 1 2 3
def func(x):
return i*x # 此时的i是3
lst.append(func) # 列表里存了四个函数
return lst


lst = num()
print(lst) # [func,func,func,func]


print([m(2) for m in num()]) # m = func m(2) = func(2) 此代码与下面代码等价

lst_new = []
for m in [func,func,func,func]:
lst_new.append(m(2))
print(lst_new) # [6 , 6 , 6 , 6] 此时的i是最后一次循环的值3 所以2*3=6


# 主要注意的点:
# ### 理解概念1
# 函数的定义处 和 函数的调用处
# 函数的定义处def 此处不会执行代码
def func():
print(123)

# 只有在调用的时候,才会去执行函数内的代码,不调用的话,不执行;
func()


# ### 理解概念2
for i in range(4):
print(i) # 0 1 2 3

# 此刻的i到底是多少?
print(i) # 3 此时的for循环已跑完 此时的i是最后一次循环的值


# ### 理解概念3 : 为什么可以拿到i=3的这个值(因为是闭包)
"""
在for循环里 i这个变量在内函数func里面被使用了
内函数使用了外函数的局部变量,该变量会延长生命周期,
暂时不释放,把 i = 3的这个值给与保留,以备下次使用
"""


# 第三十四题 def(a,b=[])这种写法有什么陷阱?
'''
b参数(默认参数)身上的值是列表,提前在内存中开辟好空间,进行存储
如果用户传递实参,那么使用用户自己的值,
如果用户没有传递实参,那么使用内存存好的列表值
'''


# 第三十五题
def func(a,b=[]): # b=[] 默认参数 提前开辟好的
b.append(a)
return b
v1 = func(1) # [1] 这个用的是默认参数 此时的b=[1]
v2 = func(2,[10,20]) # [10,20,2] 这个用的是用户自己的[10,20] 没有用默认参数
v3 = func(3) # [1,3] 这个也用的默认参数b已经有值了[1] 时的的b=[1,3]
print(v1,v2,v3) # [1,3] [10,20,2] [1,3]

# 第三十六题 (和三十五题的区别就是v1的打印顺序的不同 导致最终的值也不同)
def func(a,b=[]):
b.append(a)
return b
v1 = func(1)
print(v1) # [1]
v2 = func(2,[10,20]) #
print(v2) # # [10,20,2]
v3 = func(3)
print(v3) # [1,3]


# 第三十七题 编写一个函数实现将IP地址转换成一个整数
"""
ljust 原字符串居左,填充符号
rjust 原字符串居右,填充符号
"""
ip = "10.3.9.12"
strvar = ""
for i in ip.split("."): # 先把.拆了 i是字符串类型
bin_str = str(bin(int(i)))[2:] # bin强转二进制 将二进制的前两位0b切走 剩下的数字留下
print(bin_str)
# 补8位,不够8位的拿0来补位 最终拼接在一块
strvar += bin_str.rjust(8,"0")
print(strvar)
# 把二进制字符串转换成十进制(默认)
print(int(strvar,2)) # 167971084

# 方法二
ip = "10.3.9.12"
strvar = ""
for i in ip.split("."):
# 8 总长度8位 0 拿0来补齐8位 b代表二进制
strvar += format(int(i) , "08b")
print(strvar)
print(int(strvar,2))

# rjust
res = "alex".rjust(10,"z")
print(res) # zzzzzzalex 总长度加一起是10个;

 

# 第三十八题 查找目录下的所有文件(可能有文件的嵌套)
import os


def getallsize(pathvar): # E:\python26_27\two\ceshi
size = 0
lst = os.listdir(pathvar)# 这个路径下的所有文件以字符串的形式呈现出来
# print(lst) ["1.txt","ceshi1"]
for i in lst:
pathvar2 = os.path.join(pathvar,i) # 拼接路径 形成全新的路径 E:\python26_27\two\ceshi\1.txt
# 判断是否是文件pathvar2
if os.path.isfile(pathvar2):
size += os.path.getsize(pathvar2) # 获取文件的大小getsize 不能获取文件夹的大小 + 将所有文件大小加一起
# 判断是否是文件夹
elif os.path.isdir(pathvar2):
size += getallsize(pathvar2) # 递归文件夹(调用函数自身) 把最里面的文件 大小算出来

return size

pathvar = r"E:\python26_27\two\ceshi" # r防止转义(原字符串) \t是一个缩进0
res = getallsize(pathvar) # 算文件大小
print(res)

 

# 方法二 walk
import os
pathvar = r"E:\python26_27\two\ceshi"
gen = os.walk(pathvar) # 可以把所有文件的目录读取 这是一个生成器 可以把所有文件夹和文件遍历出来
size = 0
for root , dirs , files in gen: # files 是个列表 里面是所有的文件 可以继续遍历
for name in files:
pathvar = os.path.join(root,name) # 拼接路径
# print(pathvar)
size += os.path.getsize(pathvar)

print(size)

 

# 第三十九题 求结果 (不存在四舍五入)
# floor 地板 向下取整
# ceil 天花板 向上取整
import math
print(math.floor(5.5)) # 5
print(math.ceil(5.1)) # 6
# //地板除

# 第四十题 functools中的函数作用
from functools import reduce
# 在装饰器中使用,保留原函数的属性,加上wraps
from functools import wraps
# 装饰器
def wrapper(func):
@wraps(func) # 保留原函数的属性的作用
def inner(*args,**kwargs):
res = func(*args,**kwargs)
print("我是alex")
return res # 保留原函数的返回值(也就是 123)

return inner

@wrapper
def func():
print("我是最棒的")
return 123

res = func()
print(res)
# print(func) # <function func at 0x000001D9F7F13378> 原函数属性
# 如果装饰器不加@wraps(func) 原函数的属性就变了<function wrapper.<locals> inner at 0x000001D9F7F13378>


# 第四十一题 re 的match和search区别
"""
match : 必须从字符串的开头进行匹配
search: 从任意位置开始,匹配到就返回
"""

# 第四十二题 用python匹配HTMLtag的时候 <.> <.?>有什么区别
. 除了\n的任意字符
* ? + {3,10} 都是量词(表达数量的)

在量词的后面 加上 ? => 非贪婪
.* 贪婪匹配 按照最多值进行匹配
.*? 非贪婪匹配 按照最少值进行匹配(匹配一个就返回)


这个?没在量词后面
<.> 匹配除了\n之外的一个字符 (必须给一个)
<.?>匹配除了\n之外的一个字符或者0个字符
<.*?> 匹配tag建议使用这个

# 第四十三题 如何生成随机数
import random
random.random 随机获取 0 <= x < 1
random.randrange 随机获取指定范围内的整数 用法同range
random.uniform 随机获取指定范围内的小数

# 第四十四题 super作用
# super 可以调用父类的属性或方法,用来解决多继承之间复杂的调用关系
"""
(深度优先 广度优先 原理 去复习一下)
类.mro() => 返回继承关系的调用顺序列表
super在调用父类属性或者方法的时候,
会按照mro列表中的继承顺序依次的调用
"""

# 第四十五题 双下划线和单下划线的区别
封装: 公有public 私有 private 受保护的 protected
python : 公有成员 私有成员:双下划线来表达私有成员
受保护的: 在python中有一个约定俗称的写法,在成员的前面加一个下划线_
(可以在继承的子类当中使用,但是无法在类外调用)

双下划线(内置的魔术方法 系统自动触发调用) __init__ __call__ __new__ ....

# 第四十六题 这两方法的区别
@staticmethod 静态方法
无论是类还是对象,都可以调用,不会默认传递任何参数
@classmethod 类方法
无论是类还是对象,都可以调用,默认传递类这个参数

# 第四十七题 实现一个单例模式(加锁:避免多线程 没防住创建多个对象)
# 单例(态)模式 : 这个类无论实例化多少次,都有且只有一个对象
"""
目的:节省内存空间,提高运行效率,应用在多人操作场景中.
普通类:每生成一个对象,都会在内存中占用空间,单例模式:可以减少对象的创建;
使用场景:多人操作时,公用同一个类:比如操作mysql的增删改查
"""

from threading import Lock
class Ceshi():
__obj = None # 首先保证obj私有属性
lock = Lock() # 加锁:避免多线程 没防住创建多个对象( 我用的时候其他人排队)

def __new__(cls,*args,**kwargs): # 控制创建对象
with cls.lock: # 上锁(解锁) 上锁必须把缩进里的代码执行完后 才会给你解锁 下一个线程再操作它
if not cls.__obj: # 判断cls.__obj 是否存值 None 空的 (没有对象给你创建一个对象 有对象就不会创建的了 直接把私有的对象返回)
cls.__obj = object.__new__(cls) # 借助爸爸类object:来创建对象(cls:为哪个类创建对象)cls.__obj:用私有属性来存储父类创建的对象
return cls.__obj

obj1 = Ceshi()
obj2 = Ceshi()
obj3 = Ceshi()
print( id(obj1) , id(obj2) , id(obj3)) # 地址都一样

# 第四十八题 栈和队列区别
栈: 先进后出 或 后进先出 (电梯)
队列: 先进先出 (隧道)

# 第四十九题 以下代码输出什么
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass

# 1 1 1
print(Parent.x, Child1.x, Child2.x)
# 1 2 1
Child1.x = 2 # 为自己添加了x 用自己的
print(Parent.x, Child1.x, Child2.x)
# 3 2 3
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)

# 第五十题
'''面向对象的上下文管理(__enter__ __exit__) with语法的具体实现'''
class Context:
# 在使用with语法的时候,自动触发,功能可以返回对象
def __enter__(self):
return self

# 执行完with语法之后,执行的收尾操作
def __exit__(self,exc_type, exc_val, exc_tb):
print("close")

def do_something(self):
print("我是do_thing'")

# 为Content()实例化的对象赋值一个别名 名字叫做ctx
with Context() as ctx:
ctx.do_something()

# 附加题
# 1 列表中第二大的值(先set变集合去重 集合再排序 再取倒数第二个值)
lst = [1,2,3,100,200,200,100]
setvar = set(lst)
lst_new = sorted(setvar)
print(lst_new)
print(lst_new[-2])

# 2,3 内存管理机制 和 垃圾回收机制
# 垃圾回收机制的三个点:
计数器,垃圾回收,缓存池
# 1.计数器
特点: (内存机制 )
a = 100 (100计数为1,被引用过1次)
b = a (100计数位2,被引用过2次)
del b (100计数为1,被引用过1次)
100什么时候会被彻底的删除?就是在引用计数为0的时候,彻底删除
(没有任何变量引用100这个值,100会在内存中被删掉)

循环引用:
# ### 循环引用
# 基本案例
"""
import objgraph # 应用计数(被引用的次数)

class Person():
pass

class Dog():
pass

p = Person()
d = Dog()

print(objgraph.count("Person")) #1
print(objgraph.count("Dog")) #1

del p
del d
print(objgraph.count("Person")) #0
print(objgraph.count("Dog")) #0
"""
# 比较差异
import objgraph

class Person():
pass

class Dog():
pass

p = Person()
d = Dog()

print(objgraph.count("Person")) #1
print(objgraph.count("Dog")) #1

p.pet = d # 把d对像放到pet属性中存着(类中如果没有此属性 会自动创建此属性)
d.master = p # 同理

# 循环引用 没有被删掉
del p
del d
print(objgraph.count("Person")) #1
print(objgraph.count("Dog")) #1

"""
1
1
1
1
"""

 

# 2.分代回收 和 标记清除 (用来辅助计数引用)
标记清除 : 用来解决循环引用出现的问题,避免删不掉;


分代回收 : (垃圾回收不是每时每刻都在会后 需要有触发的条件)
三个区域分别代表数据再内存存储的的时间:
第0代 新生代(数据刚生成)
第1代 老年代(数据待了一段时间)
第2代 永久代(数据永久存在不删除)
import gc # gc垃圾回收机制
print(gc.get_threshold()) # (700, 10, 10)

# 参数1, 700 新增的对象-消亡对象个数 == 700 会触发垃圾检测时机
# 参数2, 10 代表: 当第0代对象检测次数达到10次,会触发第0代和第1代对象的检测
# 参数3, 10 代表: 当第1代对象检测次数达到10次,会触发第0代和第1代和第2代对象的检测
理解为三个齿轮:大中小 小齿轮700次中齿轮转一次

# 3.缓存池
"""为了避免频繁创建销毁变量,影响效率,提前缓存一下数据"""
1.-5 ~256 公用对象,常驻内存
2.单个字符,公用对象,常驻内存
3.不可变类型,默认开启inern驻留机制;

垃圾回收机制:以计数器为分代回收和标记清除为辅对内存数据进行清除为了内存更优化用缓存池来提升创建销毁变量的效率

# 附加题 第四题

# ### 用两个队列实现一个栈
"""
栈: 先进后出, 后进先出
队列: 先进先出,后进后出
"""
from queue import Queue

class Stack():
def __init__(self):
# 创建两个队列
self.master_queue = Queue()
self.minor_queue = Queue()


def push(self,val):
# 入栈
self.master_queue.put(val)


def pop(self):
# 出栈
# 如果队列中没有任何值,直接返回None
if self.master_queue.qsize() == 0:
return None
# 循环
while True:

# 当队列总长度为1的时候只剩一个元素,循环终止,把最后一个元素取出来,为了满足栈的先进后出的特点;
if self.master_queue.qsize() == 1: # 队列长度
value = self.master_queue.get()
break

# 将先进队列的元素拿出来的,暂时放在2号队列中存储(放先进队列的元素),1号队列长度为1时此循环终止
self.minor_queue.put(self.master_queue.get())



# 交换队列,重新循环,继续找最后一个值,依次类推
self.master_queue , self.minor_queue = self.minor_queue , self.master_queue
return value

obj = Stack()
# 进 123进入
obj.push("1")
obj.push("2")
obj.push("3")
# 出是321
print(obj.pop())# 3
print(obj.pop())# 2
print(obj.pop())# 1
print(obj.pop())# None

 



# ### 实现一个链表(单向)

一种数据结构,非连续非顺序的
链表是由一系列节点组成的元素集合。每个节点包含两部分,数据域item和指向下一个节点的指针next。

# 1.创建链表
class Node():
def __init__(self,value,next):
self.value = value # 随便给的值
self.next = next # 下一个节点的指针


head = Node("头",None)
last = head # 头

# 创建5个节点,形成一种链状的指向关系
for i in range(5):
# 创建节点对象
node = Node("d%s" % i , None) # d0 d1 d2 d3 d4
# 把当前节点存在上一个节点的next属性中
last.next = node
# 把当前节点node重置成上一个
last = node

# 查看链表的关系
print(head.value) # 头
print(head.next.value) # d0
print(head.next.next.value) # d1
print(head.next.next.next.value) # d2
print(head.next.next.next.next.value) # d3
print(head.next.next.next.next.next.value) # d4

 

# ### 2.python实现链表的逆转(从右向左)
def reverse_link_list(head):

# 要是空的,或者None 直接返回head(没有或者就一个节点)
if not head or not head.next:
return head

# 上一个节点对象
prev_node = None
# 下一个节点对象
next_node = head.next
# 当前节点对象
current_node = head
-
while True:
# 修改next , 所指向的新的对象(存储上一个对象)
current_node.next = prev_node

if not next_node: # 如果发现最后一个值是None 已经到头了 not None 已经是最后一个节点
break

# 重新获取上一个对象
prev_node = current_node
# 重新获取当前对象
current_node = next_node
# 重新获取下一个对象
next_node = current_node.next

return current_node


print("<=======>")
head = reverse_link_list(head)
print(head.value) # d4
print(head.next.value)# d3
print(head.next.next.value)# d2
print(head.next.next.next.value)# d1
print(head.next.next.next.next.value)# d0
print(head.next.next.next.next.next.value)# 头

 

标签:__,面试题,next,lst,func,print,def
From: https://www.cnblogs.com/erhuoyuan/p/16729681.html

相关文章

  • 2022-09-25-近60道MySQL经典面试题
    近60道MySQL经典面试题mysql面试常见问题学习整理2.3.17.18.19.20.44未看。1.B树和B+树之间的区别是?为什么mysql使用B+树?一个节点有多个元素;B+树也是排序了的;B+树非叶......
  • 代码随想录 两两交换链表中的节点(LeetCode 24), 删除链表的倒数第N个节点(LeetCode 1
    两两交换链表中的节点题目给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。题目链接示例:题解对于奇数个节点,最后一个节点不交换。结束条件:对于奇数个节......
  • Redis面试题
    1.项目中是否使用过redis?为什么要使用redis?使用过之前使用的都是修改某个value值,如登录账号被锁定30分钟,查看还剩余的时间,或者想将账号由锁定状态更新为未锁定状态,删......
  • 55道软件测试精品面试题分享!内附答案!
    1、你的测试职业发展是什么?测试经验越多,测试能力越高。所以我的职业发展是需要时间积累的,一步步向着高级测试工程师奔去。而且我也有初步的职业规划,前3年积累测试经验,按......
  • 前端高频面试题及答案整理(一)
    diff算法是怎么运作每一种节点类型有自己的属性,也就是prop,每次进行diff的时候,react会先比较该节点类型,假如节点类型不一样,那么react会直接删除该节点,然后直接创建新的节......
  • MySQL面试题
    MySql项目中使用的存储引擎5.0之前默认存储引擎为MyISAM引擎索引只有一种,被索引的字段值作为索引数据,叶子节点还包含该记录数据页地址不支持事务没有undolog......
  • C C++指针面试题零碎整理
    最基础的指针如下:inta;int*p=&a;答:p指向a的地址,&是取a的地址。*指的是指针中取内容的符号。2.str[]和str*的区别:charstr1[]="abc";charstr2[]="abc";c......
  • 面试题:int[] arr 和 int... arr在参数列表中是一回事儿吗?
    publicclassExer{publicstaticvoidmain(String[]args){Base1b1=newSub1();b1.add(1,2,3);}}classBase1{publicvoidadd(inta,int...arr){System.......
  • Java面试题汇总
    1、Java基础1.1、ConcurrentHashMap的底层实现,jdk1.7和jdk1.8的区别;1.2、GC的原理,涉及到的算法有哪些,GC调优怎么处理;1.3、ArrayList和LinkedList的区别是什么,底层实现是......
  • 19道高频vue面试题,顺便写一下自己的答案
    Vue路由hash模式和history模式1.hash模式早期的前端路由的实现就是基于location.hash来实现的。其实现原理很简单,location.hash的值就是URL中#后面的内容。比如下......