07.python面试之函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。

python常见的列表推导式?

[表达式 for 变量 in 列表] 或者 [表达式 for 变量 in 列表 if 条件]

简述read、readline、readlines的区别?

  • read: 读取整个文件
  • readline: 读取下一行
  • readlines: 读取整个文件到一个迭代器以供我们遍历

什么是Hash(散列函数)?

散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表

python函数重载机制?

函数重载主要是为了解决两个问题。

1。可变参数类型。

2。可变参数个数。

另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数的功能其实不同,那么不应当使用重载,而应当使用一个名字不同的函数。

好吧,那么对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处理,因为 python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。

那么对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。

好了,鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。

手写一个判断时间的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import datetime
class TimeException(Exception):
def __init__(self, exception_info):
super().__init__()
self.info = exception_info

def __str__(self):
return self.info

def time_check(func):
def inner(*args, **kwargs):
if datetime.datetime.now().year == 2022:
func(*args, **kwargs)
else:
raise TimeException("超时了")
return inner

@time_check
def test(name):
print(f'您好{name},2022新年快乐')

test("张学友")
您好张学友,2022新年快乐

编写函数的4个原则

  1. 函数设计要尽量短小
  2. 函数声明要做到合理、简单、易于使用
  3. 函数参数设计应该考虑向下兼容
  4. 一个函数只做一件事情,尽量保证函数语句粒度的一致性

函数调用参数的传递方式是值传递还是引用传递?

Python的参数传递有:位置参数、默认参数、可变参数、关键字参数。

函数的传值到底是值传递还是引用传递、要分情况:

  • 不可变参数用值传递:像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象。
  • 可变参数是引用传递:比如像列表,字典这样的对象是通过引用传递、和C语言里面的用指针传递数组很相似,可变对象能在函数内部改变。

如何在function里面设置一个全局变量

1
2
globals() # 返回包含当前作用余全局变量的字典。
global 变量 设置使用全局变量

对缺省参数的理解 ?

缺省参数指在调用函数的时候没有传入参数的情况下,调用默认的参数,在调用函数的同时赋值时,所传入的参数会替代默认参数。

  • *args是不定长参数,它可以表示输入参数是不确定的,可以是任意多个。
  • **kwargs是关键字参数,赋值的时候是以键值对的方式,参数可以是任意多对

在定义函数的时候不确定会有多少参数会传入时,就可以使用两个参数

带参数的装饰器?

带定长参数的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def check_login(func):
def inner(user, pwd):
if user=='admin' and pwd=='888888':
print("账号密码验证通过")
return func()
else:
print("账号或密码错误,请输入正确的账号密码")
return inner

@check_login
def home():
print("成功进入后台管理首页")

home('admin', '888888')
账号密码验证通过
成功进入后台管理首页

带不定长参数的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def check_login(func):
def inner(*args):
if args:
print("包含:", end="")
for part in args:
print(part, end=" ")
print("")
print("账号密码验证通过")
return func()
else:
print("账号或密码错误,请输入正确的账号密码")
return inner

@check_login
def home():
print("成功进入后台管理首页")

home('admin', '888888')
包含:admin 888888 
账号密码验证通过
成功进入后台管理首页

为什么函数名字可以当做参数用?

Python中一切皆对象,函数名是函数在内存中的空间,也是一个对象

Python中pass语句的作用是什么?

在编写代码时只写框架思路,具体实现还未编写就可以用pass进行占位,使程序不报错,不会进行任何
操作。

有这样一段代码,print c会输出什么,为什么?

1
2
3
4
a = 10
b = 20
c = [a]
a = 15

10对于字符串,数字等不可变数据类型,传递是相应的值

交换两个变量的值?

1
a, b = b, a

map函数和reduce函数?

1
2
3
4
map(lambda x: x * x, [1, 2, 3, 4]) # 使用 lambda
# [1, 4, 9, 16]
reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 相当于 ((1 * 2) * 3) * 4
# 24

回调函数,如何通信的?

回调函数是把函数的指针(地址)作为参数传递给另一个函数,将整个函数当作一个对象,赋值给调用的函数。

Python主要的内置数据类型都有哪些? print dir( ‘a ’) 的输出?

内建类型:布尔类型,数字,字符串,列表,元组,字典,集合

输出字符串’a’的内建方法

map(lambda x:x*x, [y for y in range(3)])的输出?

输出一个可迭代的map对象,转为list后结果是:[0, 1, 4]

hasattr() getattr() setattr() 函数使用详解?

hasattr(object,name)函数:

判断一个对象里面是否有name属性或者name方法,返回bool值,有name属性(方法)返回True,否则返回False。

1
2
3
4
5
6
7
8
9
class function_demo(object):
name = 'demo'
def run(self):
return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "name") # 判断对象是否有name属性,True
res = hasattr(functiondemo, "run") # 判断对象是否有run方法,True
res = hasattr(functiondemo, "age") # 判断对象是否有age属性,False
print(res)

getattr(object, name[,default])函数:

获取对象object的属性或者方法,如果存在则打印出来,如果不存在,打印默认值,默认值可选。注意:如果返回的是对象的方法,则打印结果是:方法的内存地址,如果需要运行这个方法,可以在后面添加括号().

1
2
3
4
5
functiondemo = function_demo()
getattr(functiondemo, "name")# 获取name属性,存在就打印出来 --- demo
getattr(functiondemo, "run") # 获取run 方法,存在打印出方法的内存地址
getattr(functiondemo, "age") # 获取不存在的属性,报错
getattr(functiondemo, "age", 18)# 获取不存在的属性,返回一个默认值

setattr(object, name, values)函数:

给对象的属性赋值,若属性不存在,先创建再赋值

1
2
3
4
5
6
7
8
9
class function_demo(object):
name = "demo"
def run(self):
return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "age") # 判断age属性是否存在,False
print(res)
setattr(functiondemo, "age", 18) # 对age属性进行赋值,无返回值
res1 = hasattr(functiondemo, "age") # 再次判断属性是否存在,True

综合使用

1
2
3
4
5
6
7
8
9
10
11
12
class function_demo(object):
name = "demo"
def run(self):
return "hello function"
functiondemo = function_demo()
res = hasattr(functiondemo, "addr") # 先判断是否存在
if res:
addr = getattr(functiondemo, "addr")
print(addr)
else:
addr = getattr(functiondemo, "addr", setattr(functiondemo, "addr", "北京首都"))
print(addr)

一句话解决阶乘函数?

reduce(lambda x,y : x*y,range(1,n+1))

什么是lambda函数? 有什么好处?

lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数

  1. lambda函数比较轻便,即用即扔,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下
  2. 匿名函数,一般用来给filter,map这样的函数式编程服务
  3. 作为回调函数,传递给某些应用,比如消息处理

递归函数停止的条件?

递归的终止条件一般定义在递归函数内部,在递归调用前要做一个条件判断,根据判断的结果选择是继续调用自身,还是return,返回终止递归。

终止的条件:

  1. 判断递归的次数是否达到某一限定值
  2. 判断运算的结果是否达到某个范围等,根据设计的目的来选择

下面这段代码的输出结果将是什么?请解释。

1
2
3
def multipliers():
return [lambda x: i *x for i in range(4)]
print([m(2) for m in multipliers()])

最终结果是:[6, 6, 6, 6],这个方法我们之前说过,这是一个包含匿名函数的闭包函数,我们同样将这个匿名函数和推导式拆解为普通的函数和循环

1
2
3
4
5
6
7
8
9
10
11
12
def multipliers():
# 要返回的列表
res = []
def inner(x):
return i*x
for i in range(4):
res.append(inner)
return res
res1 = []
for m in multipliers():
res1.append(m(2))
print(res1)

我们将以上代码拆解成普通的写法,大家看的相对清晰了吧,multipliers()在最后for i in range(4)之后i变为3了,并传入到了inner中,所以其实multipliers()返回的是[3, 3, 3, 3],而m(2)执行了inner,相当于x=2,所以最后返回值是[23, 23, 23, 23],即:[6, 6, ,6, 6]

什么是lambda函数?它有什么好处?写一个匿名函数求两个数的

匿名函数,省去def,一般常用于赋值

1
2
fun = lambda x, y : x+y
print(fun(3, 4))
7