函数篇
参考网址
https://blog.csdn.net/weixin_35688430/article/details/107752681
判断函数是否可调用
def add(x,y):
return x + y
print(callable(add(1,2))) # False
print(callable(add)) # True
python函数传参,很灵活,参数可以是位置参数,也可以是关键字参数
def add(x,y,z):
return x+y+z
print(add(x=1,y=2,z=3)) # 传入关键字参数
print(add(1,2,3)) # 传入位置参数
## 如果使用位置参数和关键字参数混合调用。那么位置参数必须要在关键字参数之前传入,参数不能重复
add(4,z=5,y=3) ##正确, #错误写法add(4,x=3,z=8)
可变位置参数('*')和可变关键字参数('**变量名')
-
在形参前使用 * 表示该形参是可变位置参数,可以接受多个实参(它将收集来的实参组织到一个tuple中)
-
可变位置参数必须要在位置参数后面,可变位置参数不能使用关键字传参
def sum(*args):
total = 0
for i in args:
total += i
return total
print(sum(1,2,3,4)) # 10
-
可变关键词参数(**变量名)
-
形参前使用 ** 符号,表示可以接收多个关键字参数(收集的实参名称和值组成一个字典)
-
可变关键字参数,必须要在所有参数最后面(即,参数,可变参数,可变位置参数)
-
def show_msg(**kwargs):
for k,v in kwargs.items():
print(k,'---',v)
show_msg(name='JimGreen',age=20) # name --- JimGreen age --- 20
-
keyword-only参数: 就是这个参数必须采用关键字传参
-
语法 :在一个星号之后,或一个可变位置参数(args)之后
-
理解: 假如此时不使用'关键字参数',那么该参数永远会被包裹到'*args'中
-
def fn(*args,x):
print(x,args)
fn(3,5,x=7) # 7 (3, 5)
def fn(*,x):
print(x)
fn(x=7) # 7
- 小结,参数一般顺序是: 普通参数、缺省参数、可变位置参数、keyword-only(可带缺省值)、可变关键字参数
参数解构
-
在数据类型前使用 * 或者**,把数据类型的解构解开,提取所有元素作为函数的实参
-
非字典类型使用*解构成位置参数(单层解构)
-
字典类型使用**解构成关键字参数(双层解构)
-
注意事项: 提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配
def add(x,y):
return x + y
print(add(*[1,2])) # 3
print(add(*{'x':1,'y':2})) # xy # 这里只解构了一层,即key层,所以把字符串'x'和'y'传入函数
print(add(**{'x':1,'y':2})) # 3
函数返回值
-
如果没有一条return语句被执行到,隐式调用return None
-
调用return None,可以简写为return
-
函数不能同时返回多个值,返回多个值,实质是被打包成 tuple
def show_msg():
return 1,2,3
print(show_msg()) # (1, 2, 3)
x,y,z = show_msg()
print(x,y,z) # 1 2 3
变量作用域注意事项
- 以下demo运行OK,因为全局变量可以在函数内部被调用
x = 5
def foo():
print(x)
foo() # 5
- 此时,若函数内部再次定义x,比如以下demo,就会报错
x = 5
def fn():
x = x + 1 # 定义局部变量x,注意,此时的x并不是全局x
print(x) # local variable 'x' referenced before assignment
print(fn())
'''
- 相当于在foo内部定义一个局部变量 x,那么foo内部所有x都是这个局部变量x了
- x = x +1 相当于使用了局部变量x,但是这个x还没有完成赋值,就被右边拿来做加1操作了
- 结果肯定出错
'''
## 正确写法,把x换成其他变量即可
x = 5
def fn():
y = x + 1
print(y)
print(fn()) # 6 None
### 使用 global关键字声明也可以解决这个问题
x = 5
def fn():
global x # 声明全局变量
x = x + 1
print(x)
print(fn()) # 6
print(x) # 6
函数闭包
-
在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包
-
典型 demo
def outer():
x = 1
def inner():
y = x + 1
return y
return inner
f = outer()
print(f()) # 2
-
nonlocal:将变量标记为不在本地作用域定义,而是在上级的某一级局部作用域中定义,但不能是全局作用域中定义
-
理解: 就是引用父级变量
def outer():
x = 1
def inner():
nonlocal x # 引用上面的x
y = x + 1
return y
return inner
f = outer()
print(f()) # 2
- 闭包的好处,可以捕获父函数的参数,比如使用异步的时候,前端js可以使用它来解决文件上传问题
常用函数
- isinstance(obj, class_or_tuple)
print(isinstance(1,int)) # True
print(isinstance(1,str)) # False
- issubclass(对象,类): 判断对象是否是类的'子类',返回布尔
class Foo():
pass
class Bar(Foo):
pass
class Test:
pass
print(issubclass(Bar,Foo)) # True
print(issubclass(Test,Foo)) # False
- enumerate(iterable, start=0)
- iterable 必须是一个序列,一个迭代器或其他支持迭代的对象
- 返回值是一个元组,该元组包含一个计数(从 start 开始,默认值为 0)以及遍历迭代获得的值
- (0,value1),(1,value2)
collect_data = []
for x in enumerate([2,4,6,8]):
collect_data.append(x)
print(collect_data) # [(0, 2), (1, 4), (2, 6), (3, 8)]
- zip(*iterables)
- 返回一个迭代器,用于聚合来自每个迭代器的元素
- iterables 必须是一个序列,一个迭代器或其他支持迭代的对象
list1 = [1,2,3,4]
list2 = [5,6,7,8]
data = list(zip(list1,list2))
print(data) # [(1, 5), (2, 6), (3, 7), (4, 8)]
匿名函数
- 使用lambda关键字定义匿名函数,格式为: lambda [参数列表]: 表达式
- 参数列表不需要小括号。无参就不写参数
- 冒号用来分割参数列表和表达式部分
- 不需要使用rrturn。表达式的值,就是匿名函数的返回值。表达式中不能出现等号
- lambda表达式(匿名函数)只能写在一行上,也称为单行函数
- 匿名函数往往用在未高阶函数传参时,使用lambda表达式,往往能简化代码
- 示例demo
## - 将函数对象加入列表中,通过索引访问,然后传参
# 如果这里不加索引[0],由于list对象不可调用,会报错
# 也就是说: [lambda...][0] == func 函数对象
[lambda x : x + 1][0](1) # 返回值 2
## - 其他示例
# 使用括号()写好匿名函数,然后传参
>>> (lambda x,y=3:x + y)(5)
8
>>> (lambda x,y=3:x + y)(5,6)
11