1、函数的传值到底是值传递还是引用传递,要分情况:
a.不可变参数用值传递:
像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象
b.可变参数是用引用传递的
比如像列表,字典这样的对象是通过引用传递,可变对象能在函数内部改变
2、什么是lambda函数?它有什么好处?
lambda称为匿名函数,用法:lambda args1,args2,...:表达式
lambda能和def完成同类工作,当函数逻辑过于简单时,使用lambda匿名函数代码简洁
3、字符串格式化:%和.format()的区别
字符串的fromat函数非常灵活,可以接受的参数个数不限,并且位置可以不按顺序,而且有强大的格式限定符(如填充对齐等)
4、Python是如何进行内存管理的?
1)、对象的引用计数机制
Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
引用计数增加的情况:
一个对象分配一个新名称,
将其放入一个容器中(如列表、元组或字典),
引用计数减少的情况:
使用del语句对对象别名显示的销毁,
引用超出作用域或被重新赋值
2)、垃圾回收
当一个对象的引用计数归零时,它将被垃圾回收机制处理掉。
3)、内存池机制
Python提供了对内存的垃圾回收机制,但是它将不用的内存放到内存池而不是返回给操作系统:
Pymalloc机制:为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
5、写一个函数, 输入一个字符串, 返回倒序排列的结果
#求一个字符串的倒序输出
#方式一:字符串的逆序切片
str='abcdef'
print(str[::-1])
#结果:fedcba
#方式二:字符串转成列表,列表进行翻转,再拼接成字符串
def reverse1(str):
li=list(str)
li.reverse()
return ''.join(li)
print(reverse1(str))
#结果:fedcba
#方式三:函数内新生成一个列表存入逆序取的源列表值
def reverse2(str):
li=list(str)
li2=[]
for i in range(1,len(li)+1):
li2.append(li[-i])
return ''.join(li2)
print(reverse2(str))
#结果:fedcba
#方式四:递归拼接成字符串
def reverse3(str):
if len(str)==1:
return str
else:
return reverse3(str[1:])+str[0]
print(reverse3(str))
#结果:fedcba
6、函数的默认传参问题
'''
指定def定义函数时,就已经在内存中为该函数对象分配了内存地址(当然包括其中定义的形参和默认参数对象),
所以当默认参数未被重新赋值时,不用调用函数多少次,其默认参数的对象地址都不变
'''
def extendList(a,lists=[]):
lists.append(a)
return lists
#第一次调用函数,默认参数未被重新赋值,所以默认参数对象的内存地址不变
lists1=extendList(10)
#第二次调用函数,默认参数传了新值故被重新赋值,所以会在内存中开辟一个新的内存地址来存储默认参数对象地址
#但不影响定义函数时为默认参数分配的内存地址
lists2=extendList(11,[])
#第三次调用函数,默认参数未被重新赋值,所以默认参数对象地址不变使用的仍是定义函数时分配的内存地址
#所以就会和第一次调用函数时,作用到同一个对象地址
lists3=extendList('M')
print(lists1) #结果:[10,'M']
print(lists2) #结果:[11]
print(lists3) #结果:[10,'M']
#改进版
#定义函数时lists默认参数为None,即没有为其分配内存地址
def extendList(a,lists=None):
if lists is None:
lists=[]
lists.append(a)
return lists
lists1=extendList(10)
lists2=extendList(11,[])
lists3=extendList('M')
print(lists1) #结果:[10]
print(lists2) #结果:[11]
print(lists3) #结果:['M']