Python函数

【一】函数的定义和使用

  • 函数可以提高代码可读性方便维护

  • 函数的使用必须遵循’先定义,后调用’的原则。

  • 函数的定义就相当于事先将函数体代码保存起来,然后将内存地址赋值给函数名,函数名就是对这段代码的引用,这和变量的定义是相似的。

  • 没有事先定义函数而直接调用,就相当于在引用一个不存在的’变量名’。

  • 定义函数的语法

def 函数名(参数1,参数2...):
    文件描述
    函数体
    return 值
  • def: 定义函数的关键字;
  • 函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;
  • 括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型;
  • 冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;
  • """文档描述""": 描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;
  • 函数体:由语句和表达式组成;
  • return 值:定义函数的返回值,return是可有可无的。

【1】函数的定义

(0) 空函数

def login():
    pass
  • 函数体为pass代表什么都不做,称之为空函数。
  • 定义空函数通常是有用的,因为在程序设计的开始,往往是先想好程序都需要完成什么功能,然后把所有功能都列举出来用pass充当函数体“占位符”,这将使得程序的体系结构立见,清晰且可读性强。
  • 例如要编写一个ftp程序
    • 我们可能想到的功能有用户认证,下载,上传,浏览,切换目录等功能
    • 可以先做出如下定义:
def auth_user():
    "user"
    
def download_file():
    "download"
def update_file():
    "upload"
    pass

def ls():
    "list"
    pass

def cd():
    "change"
    pass

(1)无参无返回值

def interactive():
    user = input("请输入用户名:").strip()
    pwd = input("请输入密码:").strip()

(2)有参无返回值

  • 参数是函数的调用者向函数体传值的媒介
def greet(name):
    print(f"hello,{name}!")

greet('world')


def acive(greet):
    usernaem = input(greet)

acive("请输入用户名:")
acive("请输入密码:")

(3)有多个参数无返回值

def add_numbers(a,b):
    result = a + b
    print(f"The sum of {a} and {b} is {result}")

add_numbers(3,5)

(4)多个参数一个返回值

def add_numbers(a,b):
    result = a + b
    print(result)
    return result

res = add_numbers(3,5)
print(res)

(5)多个参数多个返回值

def rectangle_info(length,width):
    area = length * width
    perimeter = 2 * (length + width)
    return area,perimeter

area,perimeter =  rectangle_info(4,5)
print(f"小妹年龄{area},大哥年龄{perimeter}")

【2】函数的三种调用方式

(1)直接调用

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

result = add(3,5)
print(result)

(2)表达式调用

def subtract(x,y):
    return x - y

opention = subtract

result = opention(10,5)
print(result)
def add(a,b):
    res = a + b
    print(f"这是add函数 :>>>{res}")
    return res

def subtrace(a,b):
    res = a - b
    print(f"这是subtrace函数 :>>>{res}")
    return res

func_dict = {1:add,2:subtrace}
func_id = input("请输入功能 id :>>>>>")
func = func_dict.get(int(func_id))

a = input("请输入参数 a :>>>>")
b = input("请输入参数 b :>>>>")
res = func(int(a),int(b))
print(res)

(3)函数作为参数

def multiply(x,y):
    return x * y

def operate(func,x,y):
    return func(x,y)

result = operate(multiply,4,6)

print(result)

【三】函数的参数

【1】形参和实参的介绍

  • 函数的参数分为形式参数和实际参数,简称形参和实参
    • 形参即在定义函数时,括号内声明的参数。
      • 形参本质就是一个变量名,用来接收外部传来的值。
    • 实参即在调用函数时,括号内传入的值
      • 值可以是常量、变量、表达式或三者的组合:
def add(x,y):
    return x + y

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

x = 5
y = 6

res_second = add(x,y)
print(res_second)

res_third = add(10 * 2, 10 * add(3,4))
print(res_third)

a = 2
res_forth = add(a,10 * add(3,4))
print(res_forth)
  • 在调用有参函数时,实参(值)会赋值给形参(变量名)。
  • 在Python中,变量名与值只是单纯的绑定关系,而对于函数来说,这种绑定关系只在函数调用时生效,在调用结束后解除。

【2】位置参数

  • 位置即顺序,位置参数指的是按顺序定义的参数
  • 需要从两个角度去看:
    • 在定义函数时,按照从左到右的顺序依次定义形参,称为位置形参
    • 凡是按照这种形式定义的形参都必须被传值

(1)有位置参数而不传值会报错

def register(name,age,sex):
    print(name,age,sex)

register() # TypeError:缺少3个位置参数
'''
Traceback (most recent call last):
  File "E:\PycharmProjects\demo\venv\demo.py", line 46, in <module>
    register()
TypeError: register() missing 3 required positional arguments: 'name', 'age', and 'sex'
'''

(2)不按位置传参会导致变量错误

def register(name,age,sex):
    print(name,age,sex)

register(18,"男","Bill")

# 18 男 Bill

(3)对应位置传参

def register(name,age,sex):
    print(name,age,sex)
    
register("张飞",18,"男")
# 定义位置形参:name,age,sex,三者都必须被传值

(4)小结

  • 在调用函数时,按照从左到右的顺序依次定义实参,称为位置实参
  • 凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应

【3】关键字参数

在调用函数时,实参可以是key=value的形式,称为关键字参数

  • 凡是按照这种形式定义的实参,可以完全不按照从左到右的顺序定义,但仍能为指定的形参赋值

(1)按顺序传参

def register(name,age,sex):
    print("{},{},{}".format(name,age,sex))

register(name="zhang",age=18,sex="男")

(2)不按顺序传参

def register(name,age,sex):
    print("{},{},{}".format(name,age,sex))

register(name="男",age="zhangsan",sex="18")

(3)位置和关键字混合使用

def register(name,age,sex):
    print("{},{},{}".format(name,age,sex))

register("zhangsan",age="18",sex="男")

【4】默认参数

  • 在定义函数时,就已经为形参赋值,这类形参称之为默认参数
    • 当函数有多个参数时,需要将值经常改变的参数定义成位置参数,而将值改变较少的参数定义成默认参数。
    • 例如编写一个注册学生信息的函数
    • 如果大多数学生的性别都为男,那完全可以将形参sex定义成默认参数

(1)默认参数不传值

def register(name,age,sex="男"):
    print(name,age,sex)

register("zhangsan",age=18)

(2)默认参数传值

(1)默认参数初始化
  • 默认参数必须在位置参数之后
  • 默认参数的值仅在函数定义阶段被赋值一次
def register(name,age,sex="男"):
    print('Name:%s Age:%s Sex:%s' % (name, age, sex))

register("zhangsan", age=18, sex="女")
(2)默认参数为可变数据类型
  • 默认参数的值通常应设为不可变类型
  • 每次调用是在上一次的基础上向同一列表增加值
def append_list(num,list_inner=[]):
    list_inner.append(num)
    return list_inner

res_1 = append_list(1)
print(res_1)

res_2 = append_list(2)
print(res_2)

res_3 = append_list(3)
print(res_3)
(3)默认参数为空
  • 默认参数的值通常应设为不可变类型
def append_list(num, list_inner=None):
    if list_inner is None:
        list_inner = []
    list_inner.append(num)
    return list_inner


# 传入参数 1 ,对应在函数中的参数为空
# 在函数内部会有一个判断,不传值为空,则列表重置为空
res_1 = append_list(1)
print(res_1)  # [1]

# 在函数内部会有一个判断,不传值为空,则列表重置为空
res_2 = append_list(2)
print(res_2)  # [2]

# 在函数内部会有一个判断,不传值为空,则列表重置为空
res_3 = append_list(3)
print(res_3)  # [3]

【5】可变长参数

  • 参数的长度可变指的是在调用函数时,实参的个数可以不固定
    • 而在调用函数时,实参的定义无非是按位置或者按关键字两种形式
    • 这就要求形参提供两种解决方案来分别处理两种形式的可变长度的参数

(1)可变长位置参数(*args)

  • 参数的长度可变指的是在调用函数时,实参的个数可以不固定
    • 而在调用函数时,实参的定义无非是按位置或者按关键字两种形式
    • 这就要求形参提供两种解决方案来分别处理两种形式的可变长度的参数
1.任意类型参数
  • 如果在最后一个形参名前加 * 号,那么在调用函数时,溢出的位置实参,都会被 * 接收,以元组的形式保存下来赋值给该形参
# 实参1、2、3按位置为形参x、y、z赋值
# 多余的位置实参4、5、6、7都被*接收,以元组的形式保存下来,赋值给args
# 即args=(4, 5, 6,7)
  • 如果我们想要求多个值的和,*args 就派上用场了
def add(*args):
    res = 0
    for i in args:
        res += i
    return res

res = add(1,2,3,4,5)
print(res)
2.解包
  • 如果我们事先生成了一个列表,仍然是可以传值给 *args
def foo(x,y,*args):
    print(x)
    print(y)
    print(args)

L = [3,4,5]
foo(1,2,L)
  • 注意:如果在传入 L 时没有加 * ,那 L 就只是一个普通的位置参数了

(2)可变长关键字参数(**kwargs)

  • 如果在最后一个形参名前加**号,那么在调用函数时,溢出的关键字参数,都会被 ** 接收,以字典的形式保存下来赋值给该形参
def foo(x,**kwargs):
    print(x)
    print(kwargs)

foo(y=2, x=1, z=3)
  • 如果形参为常规参数(位置或默认),实参仍可以是 ** 的形式
def foo(x,y,z=3):
    print(x)
    print(y)
    print(z)

foo(**{'x': 1, 'y': 2})

(3)组合使用

def register(name,age,*args,**kwargs):
    user_dict = {'name':name,'age':age}
    if args:
        user_dict['additional_info'] = args
    if kwargs:
        user_dict.update(kwargs)
    return user_dict

user_dict = register("Dream",18,"handsome",hobby=["music"])
print(user_dict)

# {'name': 'Dream', 'age': 18, 'additional_info': ('handsome',), 'hobby': ['music']}

【6】命名关键字参数

(1)函数内判断

  • 在定义了**kwargs参数后,函数调用者就可以传入任意的关键字参数key=value
  • 如果函数体代码的执行需要依赖某个key,必须在函数内进行判断
def register(name,age,**kwargs):
    if 'sex' in kwargs:
        # 有sex参数
        pass
    if 'height' in kwargs:
        # 有height参数
        pass

(2)命名关键字传参

  • 想要限定函数的调用者必须以key=value的形式传值
    • Python3提供了专门的语法:+
      • 需要在定义形参时,用 * 作为一个分隔符号,* 号之后的形参称为命名关键字参数。
    • 对于这类参数,在函数调用时,必须按照key=value的形式为其传值,且必须被传值
def register(name,age,*,sex,height):
    pass

register('zhang',18,sex='male',height='1.8m')

register('zhang',18,'male','1.8m')

register('zhang',18,height='1.8m')

【7】混合使用

  • 综上所述所有参数可任意组合使用,但定义顺序必须是:
    • 位置参数默认参数\*args命名关键字参数\**kwargs
  • 可变参数*args 与关键字参数**kwargs通常是组合在一起使用的
  • 如果一个函数的形参为 **args**kwargs,那么代表该函数可以接收任何形式、任意长度的参数
def wrapper(*args,**kwargs):
    pass

def func(x, y, z):
    print(x, y, z)


def wrapper(*args, **kwargs):
    func(*args, **kwargs)


wrapper(1, z=3, y=2)
# 1 2 3
posted @ 2023-12-11 16:05  Fredette  阅读(52)  评论(0)    收藏  举报