难度指数: ★★
重要指数: ★★★★
这个题目要考察的是你对python函数可变参数的理解。
python可变参数分为两种:
在定义函数时,有时候你并不希望参数的个数是固定的,这种设计在实际工作中很常见。
def func(*args):
print(args, type(args))
sum_res = 0
for item in args:
sum_res += item
return sum_res
print(func(2))
print(func(2, 3, 4))
你可以看到,我在定义func时,使用*args, args只是个名字,你可以随意修改,关键是前面有一个星。有了这个星,函数调用时传递多少个参数就变成了一个很随意的事情,所有传入的参数将被放入到一个元组中,因此args的类型是tuple元组.
def print_score(**kwargs):
print(kwargs, type(kwargs))
for course, score in kwargs.items():
print(course, score)
print_score(yuwen=89, shuxue=94)
在调用函数时,以关键字参数的形式进行参数传递,最终这些key-value对将组装成字典,kwargs的类型是dict。个人理解,**kwargs就是一种为了偷懒而做的设计,当函数需要传入很多参数(多达10几个)时,使用**kwargs定义函数是非常方便的。
回答这个问题有两个要点:
难度指数: ★★
重要指数: ★★
首先要明确,对于lambda准确称呼应当是lambda表达式,这个表达式创建了一个匿名函数。
何为匿名函数呢? 我们用def 关键字创建的函数,有自己的名字,有自己的函数文档
def score(x):
"""
返回分数
:param x:
:return:
"""
return x[1]
print(score.__name__)
print(score.__doc__)
上面这段代码执行结果为
score
返回分数
:param x:
:return:
使用def定义的函数,有名字,有文档,而使用lambda表达式创建的函数,是没又名字和函数文档的,不然也就不会叫它匿名函数了
下表详细展示了两者的区别
函数 | 是否有名字 | 是否有函数文档 | 代码行数要求 | 是否自动返回结果 |
---|---|---|---|---|
def 创建的函数 | 是 | 是 | 无限制 | 否 |
lambda创建的函数 | 否 | 否 | 一行 | 是 |
要在合适的场景应用lambda表达式
下面这段代码计算列表里所有数据的乘积
lst = [2, 1, 3]
product = 1
for item in lst:
product *= item
print(product)
如果改为reduce算法,则可以这样写
from functools import reduce
lst = [2, 1, 3]
product = reduce(lambda x, y: x * y, lst, 1)
print(product)
lambda表达式作为reduce函数的参数来使用,如果你在工作中需要使用pyspark,那么,lambda表达式应用的会更加频繁
参考文章 python lambda表达式精讲
func = lambda a, b: a*b
print(func(3, 4))
lambda表达式的结果是一个匿名函数,将这个匿名函数赋值给变量func,接下来,你可以像使用函数一样来使用func,不过这是PEP8中明确建议禁止的行为,lambda表达式最好只作为其他函数的参数来使用。
难度指数: ★★
重要指数: ★★★
在C++中,函数传参,可以选择传值,或者传址,理解这两者的区别,需要你对指针很熟悉。
如果你没有C++语言的基础,没关系,我们直接来看python的传参。python的函数传参,没有传值和传址的分别,一律是传对象的引用。
如果传入参数是可变对象,例如字典,列表,那么就相当于传址,你可以对传入的对象进行修改,如果传入参数是不可变对象,那么就相当于传值,不能对传入的对象进行修改。
回答这个问题,一定要指出python传参,传的是对象的引用。
难度指数: ★★★★★
重要指数: ★★★★★
面试必考题目,对装饰器的理解程度,几乎可以代表你对python这门语言的掌握程度,以下3个关键点,务必掌握
python中一切皆对象,函数也是对象,正因为函数也是对象,所以,函数可以作为一个函数的参数
import time
def cost(func):
t1 = time.time()
result = func()
t2 = time.time()
print(f"{func.__name__}执行时长: {t2-t1}")
def test():
time.sleep(1.5)
cost(test)
在调用执行cost函数时,将test函数做为参数传入,在cost函数内,执行test函数。
python中,一切皆对象,所以函数可以作为另一个函数的返回值
import time
def cost(func):
def wrapper():
t1 = time.time()
result = func()
t2 = time.time()
print(f"{func.__name__}执行时长: {t2-t1}")
return result
return wrapper
def test():
time.sleep(1.5)
new_test = cost(test)
new_test()
函数cost的返回值是wrapper,它是一个函数,cost函数的返回值赋值给new_test, test_test() 等价于wrapper(),调用test_test就是在调用等价于wrapper。
wrapper这个函数内部,调用执行了func, func是什么,是函数cost的参数,别忘了你是如何调用执行cost函数的
new_test = cost(test)
func这个参数,实际传入的是函数test,wrapper内部调用的是test函数,统计的是它的执行时长。
在一个内部函数中,对外部作用域的变量进行引用,(并且一般外部函数的返回值为内部函数),那么内部函数就被认为是闭包。
如何理解这段话,以2.5.2 中的代码为例,在函数wrapper内部,引用了外部作用域的func, 并且外部函数cost的返回值就是内部函数wrapper,内部函数wrapper就被认为是闭包。
闭包的概念,又牵扯出嵌套作用域,函数作用域,关于作用域和装饰器,更详细的讲解请参考酷python---装饰器
经过2.5 的讲解,你应当已经对装饰器有了基本认识,参考文章里,对装饰器有着更深入的讲解,下面是参考代码
import time
from functools import wraps
def cost(func):
@wraps(func)
def warpper(*args, **kwargs):
t1 = time.time()
res = func(*args, **kwargs)
t2 = time.time()
print(func.__name__ + "执行耗时" + str(t2-t1))
return res
return warpper
@cost
def test(sleep_time):
"""
测试装饰器
:param sleep_time:
:return:
"""
time.sleep(sleep_time)
test(0.3)
QQ交流群: 211426309