你好,我是测试小牛。之前给大家写过一篇软件测试面经文章,Python部分答案来啦~
一.Python的可变类型和不可变类型分别是哪些?
可变数据类型:列表、字典、可变集合。
不可变数据类型:数字、字符串、元组、不可变集合。
二.*arg和**kwarg的区别?
*args代表位置参数,它会接收任意多个参数并把这些参数作为元祖传递给函数。
**kwargs代表的关键字参数,返回的是字典,位置参数一定要放在关键字前面
三.谈谈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]
四.说下生成器,迭代器,可迭代对象区别和应用场景?
含有__iter__和__next__方法 (包含__next__方法的可迭代对象就是迭代器)
包括含有yield这个关键字,生成器也是迭代器,调动next把函数变成迭代器。
应用场景:
range/xrange
- py2:range(1000000) ,会立即创建,xrange(1000000)生成器
- py3:range(10000000)生成器
一个类内部实现__iter__方法且返回一个迭代器。
应用场景:
- wtforms中对form对象进行循环时候,显示form中包含的所有字段。
class LoginForm(Form):
name = simple.StringField(
label='用户名',
validators=[
validators.DataRequired(message='用户名不能为空.'),
validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
],
widget=widgets.TextInput(),
render_kw={'class': 'form-control'}
)
pwd = simple.PasswordField(
label='密码',
validators=[
validators.DataRequired(message='密码不能为空.'),
validators.Length(min=8, message='用户名长度必须大于%(min)d'),
validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
)
form = LoginForm()
for item in form:
print(item)
五.静态方法和类方法区别?
尽管 classmethod 和 staticmethod 非常相似,但在用法上依然有一些明显的区别。classmethod 必须有一个指向类对象的引用作为第一个参数,而 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
六.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
七.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__()方法。