注
- 函数的本质
- 就是一串内存地址
- 可以赋值、可以作为容器类型的元素、函数的参数和返回值 —— 第一类对象
- 一般情况下形参定义了多少个,在函数调用的时候就要穿多少个,除非使用了 形参默认值 或 动态参数,不然会报错
- 实参定义顺序:必须先按照位置传参, 再按照关键字传参数
- 形参定义顺序:位置参数, *args, 默认参数, 关键字参数, **kwargs
1. 函数的定义
def fn(a):
print(a)
return a
return_val = fn('传参')
2. 函数的返回值
- 没有返回值 -> 返回 None
def fn(a):
print(a)
return_val = fn('传参') # None
- 返回多个值用多个变量接收
def fn(a):
print(a)
return 1, 2, 3
r1, r2, r3 = fn('传参')
- 返回多个值用一个变量接收 -> 接收到的是 元组
def fn(a):
print(a)
return 1, 2, 3
return_tuple = fn('传参') # (1, 2, 3)
3. 实参
- 按照位置传参
def fn(a, b):
print(a, b)
fn('data1', 'data2')
- 按照关键字传参
def fn(a, b):
print(a, b)
fn(b='data2', a='data1')
- 混合使用 按位置传参 和 按关键字传参 -> 必须先按照位置传参, 再按照关键字传参数
def fn(a, b, c, d):
print(a, b, c, d)
fn(1, 2, d=4, c=3)
4. 形参
- 形参默认值
def fn(a, b=2):
print(a, b)
fn(1)
ef fn(a, b=2):
print(a, b)
fn(1, 3)
- 形参默认值陷阱 -> 如果默认参数的值是一个可变数据类型,那么每一次调用函数的时候,如果不传值就共用这个数据类型的资源
def trap(lis=[]):
lis.append(1)
print(lis)
trap()
trap()
trap()
def trap(key, dic={}):
dic[key] = 'val'
print(dic)
trap(1)
trap(2)
trap(3)
5. 动态形参
- *形参名 -> 约定俗成形参名: args -> 接收的是按照位置传参的值,组织成一个元组
def fn(*args):
print(args) # 元组: (1, 2, 3, 4, 5, 6)
fn(1, 2, 3, 4, 5, 6)
- **形参名 -> 约定俗成形参名: kwargs -> 接受的是按照关键字传参的值,组织成一个字典
def fn(**kwargs):
print(kwargs) # 字典: {'k3': 'v3', 'k2': 'v2', 'k1': 'v1'}
fn(k1='v1', k2='v2', k3='v3')
- *args **kwargs 混合使用
- 使用场景: 当函数不知道有没有参数或者不确定参数个数的时候可以使用 *args **kwargs
def fn(*args, **kwargs):
print(args) # (1, 2, 3)
print(kwargs) # {'k1': 'v1', 'k3': 'v3', 'k2': 'v2'}
fn(1, 2, 3, k1='v1', k2='v2', k3='v3')
def fn(*args, default='形参默认值', **kwargs):
print(args) # (1, 2, 3)
print(default) # '形参默认值'
print(kwargs) # {'k1': 'v1', 'k3': 'v3', 'k2': 'v2'}
fn(1, 2, 3, k1='v1', k2='v2', k3='v3')
6. 动态实参
- *序列 -> 在序列(列表,元组)前面加上*,就是将该序列按照顺序打散传递给函数中
list1 = [1, 2, 3]
def fn(d1, d2, d3):
print(d1, d2, d3) # 1 2 3
fn(*list1) # 加了* 就类似于 fn(1, 2, 3)
list1 = [1, 2, 3]
def fn(*args):
print(args) # (1, 2, 3)
fn(*list1) # 加了* 就类似于 fn(1, 2, 3)
- **字典 -> 在字典前面加上**,就是将该字典打散传递给函数中
dict1 = {'k1': 1, 'k2': 2, 'k3': 3}
def fn(k1, k2, k3):
print(k1, k2, k3) # 1 2 3
fn(**dict1) # 加了 ** 类似于 fn(k1=1, k2=2, k3=3)
dict1 = {'k1': 1, 'k2': 2, 'k3': 3}
def fn(**kwargs):
print(kwargs) # {'k1': 1, 'k2': 2, 'k3': 3}
fn(**dict1) # 加了 ** 类似于 fn(k1=1, k2=2, k3=3)
7. 混合使用所有类型
list1 = [1, 2, 3]
dict1 = {'k1': 1, 'k2': 2, 'k3': 3}
def fn(name, age, *args, default='默认值', top, **kwargs):
print(name) # Kevin
print(age) # 18
print(args) # ('175cm', '120kg', 1, 2, 3)
print(top) # 12
print(default) # 默认值
print(kwargs) # {'k1': 1, 'k2': 2, 'k3': 3, 'left': 13}
fn('Kevin', 18, '175cm', '120kg', *list1, top=12, left=13, **dict1)
8. 给函数添加自定义属性
def fn():
return 1
fn.attr = '自定义属性'
print(fn.attr) # '自定义属性'
9. .__name__ -> 获取函数的函数名
def fn():
print('函数')
fn_name = fn.__name__ #fn
10. .__doc__ -> 获取函数的注释 没啥用
def fn():
'''
函数的注释
:return:
'''
print('函数')
fn_doc = fn.__doc__
11. 函数注释
def func():
'''
这个函数实现了什么功能
参数1:
参数2:
:return: 是字符串或者列表的长度
'''
pass
12. 在函数里面可以直接对函数外的列表,字典,集合进行修改
lis = [1, 2, 3]
dic = {'a': 1, 'b': 2}
def fn():
lis.append(4)
dic['c'] = 3
fn()
print(lis) # [1, 2, 3, 4]
print(dic) # {'a': 1, 'b': 2, 'c': 3}
13. 什么是函数?什么是方法?
- 一般情况
- 写在模块中的叫函数,写在类中的叫方法
- 特殊情况
- 写法: 对象.fn() -> 叫方法
from types import FunctionType, MethodType
class Foo(object):
def fn(self):
return '值'
obj = Foo()
# 验证是否是函数
print(isinstance(obj.fn, FunctionType)) # False
# 验证是否是方法
print(isinstance(obj.fn, MethodType)) # True
- 写法: 类.fn() -> 叫函数
from types import FunctionType, MethodType
class Foo(object):
def fn(self):
return '值'
# 验证是否是函数
print(isinstance(Foo.fn, FunctionType)) # True
# 验证是否是方法
print(isinstance(Foo.fn, MethodType)) # False