py_14 函数基本使用和参数

2020-08-11  本文已影响0人  阿登20

函数

一、引入
二、定义函数
    作用:提高编写效率,代码重复利用 代码简洁 方便修改,更易扩展 保持代码的一致性
    三种定义方式:
        1.无参函数 2. 有参函数 3. 空函数
三、函数调用
    1. 语句的形式:只加括号调用
    2. 表达式:
    3. 函数调用可以当参数
四、函数返回值
    1.  没有return或者return 或者return None ===> 返回None
    2. 返回一个值:return x
    3. 返回多个值,逗号分隔开,返回的是一个元组: return 1,3,5
五、函数的参数
python中所有值的传递,传递的都不是值的本身,而是值的引用,即内存地址
形参:定义时的参数,也是局部变量
实参:调用的传参值
位置参数:一个萝卜一个坑,不能多不能少,位置一一对应
默认参数:函数定义时,调用时能少写实参,放在位置参数后面
        定义默认参数时,必须是不可变类型
        可变类型的默认参数,在函数内部修改,默认参数也会修改
关键字参数:
        函数调用,key=value不用按照顺序书写,放在位置参数后面
可变参数:*args,**kwargs。分别是元组 和 字典
命名关键字参数:没有可变参数时候,前面要用*占坑。
            传参时,书写要key=value的格式
顺序书写:位置参数,默认参数,可变参数,命名关键字参数
    

一、引入

比如一个修理工会事先准备好螺丝刀、锤子等工具,这样在进行修理的过程中,需要用到拧螺丝的功能时就直接拿来螺丝刀使用,需要用到锤击物体的功能时就直接拿来锤子使用,而无需临时制造。这个例子的核心在于’事先准备好工具’,遇到应用场景时’拿来就用’,。

在程序中,具备某一功能的‘工具’指的就是函数,‘事先准备工具’的过程即函数的定义,‘拿来就用’即函数的调用

二、定义函数

1.定义

# 定义
def 函数名(参数名1,参数名2):
    """文档字符串"""
    # 函数体
    return 表达式


def add(x:int, y:int) -> int: # x,y为int型,函数返回为int型,只是注释,参数格式非法不会报错
    pass 
    return x+y
  1. def: 定义函数的关键字;

  2. 函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;

  3. 括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型;

  4. 冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;

  5. """文档字符串""": 描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;

  6. 函数体:由语句和表达式组成;

  7. return 值:定义函数的返回值,return是可有可无的。

函数的作用

.为什么使用函数:
1.不适用函数: 组织结构不清晰,可毒性差
2.代码冗余
3.可维护性、扩展性差

作用:
    提高编写效率,代码重复利用
    代码简洁
    方便修改,更易扩展
    保持代码的一致性

2.三种定义方式:

形式一:无参函数

def func():
    print("无参数函数")
# 调用
func()

# 定义函数发生的事情
# 1. 将申请内存空间保存函数体代码
# 2. 将上诉内存地址绑定给函数名
# 3. 定义时不会执行函数体代码,但是检测代码语法。只有调用时才会执行函数代码

# 调用函数发生的事情
print(func) # <function func at 0x0000000002936488>
# 1. 通过函数名找到函数的内存地址
# 2. 然后加括号就是在触发函数体代码的执行
func()
# 示范1
def bar(): # 函数定义会检测函数体代码语法
    print("i am adeng")
def foo():  # 函数定义会检测函数体代码
    bar()
    print("阿登")
foo() # 调用时才会执行函数代码

# 示范2
def foo():
    bar()
    print("阿登")

def bar():
    print("i am adeng")
foo()
# 示范3
def foo():
    bar()
    print("阿登")
foo() # 会报错 调用时报错,因为函数体中的代码bar() 找不到这个函数
def bar():
    print("i am adeng")

形式2:有参函数

# 形式2:有参函数
# 如果把函数比喻成一个工厂,那么参数就是原材料,返回值是产品
def func(x,y): # x,y 材料
    return x+y # 产品
func(1,2) # 1传给x  2传给y,位置参数 一一对应
print(func.__doc__)

形式3:空函数

# 形式三:空函数
def func():
    pass # 占位符
func()
# 构思代码的时候使用 空函数

三、函数调用

1. 语句的形式:只加括号调用

def foo():
    print("adneg")

def add(x,y):
    return x+y

foo()

2. 表达式:

# 赋值表达式
res = add(1,2)
print(res)
# 数学表达式
res = add(1,2)*10
print(res)

3.函数调用可以当参数

res1= add(1,add(1,2))
print(res1)

四、函数返回值

  1. 没有return或者return 或者return None ===> 返回None

  2. 返回一个值:return x

  3. 返回多个值,逗号分隔开,返回的是一个元组: return 1,3,5

# 函数体代码一旦运行到return会立刻终止函数的运行。
def add(x,y):
    print('111')
    return x+y # return下面代码不会执行
    print("222")

res = add(1,2)

# 1 没有return或者return 或者return None ===> 返回None
# 2 返回一个值:return x
# 3.返回多个值,逗号分隔开,返回的是一个元组: return 1,3,5

五、函数参数

形参:定义时的参数,也是局部变量
实参:调用的传参值
位置参数:一个萝卜一个坑,不能多不能少,位置一一对应
默认参数:函数定义时,调用时能少写实参,放在位置参数后面
        定义默认参数时,必须是不可变类型
        可变类型的默认参数,在函数内部修改,默认参数也会修改
关键字参数:
        函数调用,key=value不用按照顺序书写,放在位置参数后面
可变参数:*args,**kwargs。分别是元组 和 字典
命名关键字参数:没有可变参数时候,前面要用*占坑。
            传参时,书写要key=value的格式
顺序书写:位置参数,默认参数,可变参数,命名关键字参数

image.png

默认参数

1.默认参数的值在函数定义阶段被赋值的,被赋值的是内存地址

2.python中所有值的传递,传递的都不是值的本身,而是值的引用,即内存地址

# python中所有值的传递,传递的都不是值的本身,而是值的引用,即内存地址
m =2
def dunc(x,y=m): # y=> 2的内存地址
    print(x,y)
m =3
func(1) # print(1,2) 不是print(1,3)

2.虽然默认值可以被指定为任意类型,但是不推荐使用可变类型

# 默认参数是可变类型
# 默认参数必须在位置参数 右边
def foo(n, arg=[]): arg=> []的内存地址
    arg.append(n)
    return arg
print(foo(1)) #   [1]
print(foo(2)) #   [1, 2]

# 解决方案如下
def foo(n, arg=None):
    if arg is None:
        arg = []
    arg.append(n)
    return arg
print(foo(1))  #  [1]
print(foo(2)) #   [2]

3.函数定义时默认参数的位置必须放在位置参数后面

可变参数:*args,**kwargs分别是元组 和 字典

# *形参名:用来接收溢出的位置参数,溢出的位置实参会被*args接收,args是一个元组
def func(x,y,*z):
    print(x,y,z)

func(1,2,3,4,5) # 1 2 (3, 4, 5)
l = 7,8
func(1,2,*l) # 1 2 (7, 8)
func(1,2,l) # 1 2 ((7, 8),)

# 求一个序列的和
def my_sum(*args):
    res = 0
    for i in args:
        res +=i
    return res
res = my_sum(1,2,4,7)
print(res) #  14
# **形参名:用来接收溢出的关键字实参,**会将溢出的关键字实参保存成字典,赋值给紧跟其后的形参名**kwargs.kwargs是一个字典
*args放在**kwargs前面

def func(x,y,**kwargs):
    print(x,y,kwargs)

func(1,y=2,a=3,b=4,c=5) # 1 2 {'a': 3, 'b': 4, 'c': 5}
l = {"a":5,"b":8}
func(1,2,**l) # 1 2 {'a': 5, 'b': 8}


*和** 混用
def index(x,y,z):
    print(x,y,z)
# 函数定义*和**是打包:*是实参位置参数打包成元组,**是实参关键字参数key=value打包成字典
def wrapper(*args,**kwargs):# args=(1,) kwargs ={"z":2,"y":3}
    index(*args,**kwargs) # index(1,z=2,y=3) # 函数调用*和** 是解包
  # index(*(1,),**{"z":2,"y":3})
  # index(1,x=2,y=3)

wrapper(1,z=2,y=3)  # 1 3 2
# 上面wrapper传参的格式,其实是受index函数的格式。

命名关键字参数 *


def func(a,b,*,c,d):
    print(a,b,c,d) # 1 2 3 4
func(1,2,c=3,d=4)

def bar(a,b,*args,c,d):
    print(a,b,c,d) # 1 2 3 4
bar(1,2,5,6,7,c=3,d=4)

def my(a,*,b=4,c): # 这里c不是位置参数,是命名关键字参数,放在了位置参数a后面没有报错
    print(a,b,c) # 1 4 22
my(1,c=22)

# 书写顺序 位置参数 默认参数 *args 命名关键字 **kwargs
def bar(a,b,*args,c,d,**kwargs): # **kwargs 放在命名关键字c,d之前会报错
    print(a,b,c,d) # 1 2 3 4
bar(1,2,5,6,7,c=3,d=4)

定义函数形参书写顺序:位置参数 默认参数 *args 命名关键字 **kwargs

上一篇 下一篇

猜你喜欢

热点阅读