我的Python学习日记(六):函数

本文介绍了Python中的函数概念,包括基本结构、定义方法、参数传递(类型、位置和关键字)、lambda函数、类型提示和函数装饰器的使用。通过实例展示了如何组织和调用函数,以及可变参数和默认参数的运用。
摘要由CSDN通过智能技术生成

我的Python学习日记


DateLog
2023.12.01完成编写
2023.12.046.1 基本结构与定义方法中添加类型提示(Type Hints)
2023.12.05添加6.5 函数装饰器

6. 函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
合理定义函数可以提高应用的模块性、代码的重复利用率和可读性,减少编程工作量,增加参数可变性。
除了python自带的形如print()等的内建函数,我们还可以自己定义函数。

6.1 基本结构与定义方法

一般来说,函数具有以下的结构:

  1. def 关键字开头,后接函数标识符名称、圆括号()和冒号:
  2. 函数的传入参数放在圆括号中,与C语言类似
  3. 函数体通过缩进来标定范围而非C语言时的 ‘{}’
  4. 函数以return作为结束,返回一个值给调用处,若return后没有表达式则返回None
格式一般为
def  函数名(参数列表(可选)):
    函数体
  1. 为了便于阅读代码以及静态分析,函数可以通过使用冒号:以及->分别对参数和返回值进行类型提示(Type Hints):
def 函数名(参数1: int, 参数2: str)  -> int:
    函数体
def add1(num1: int,num2: int) ->int:
    sum1=num1+num2
    return sum1

def add2(num1: int,num2: int) ->None:
    sum1=num1+num2
    return 
# 两个函数都是将两个传入的参数相加,但add2没有返回值
print(add1(1,2)) # 3
print(add2(1,2)) # None

在VSCode中,当鼠标悬停在函数名或调用该函数时,会分别出现以下提示:
悬停时
调用时


6.2 函数调用

函数定义了就是为了要调用,与C语言一样,使用函数名+参数进行调用
如果函数有返回值,那么对该函数的调用语句实际上就是代表了一个值,
如果该函数没有返回值,那么调用该函数相当于运行其中代码产生影响而不作为值参与到程序运行中

import random as rd

def shuffle(list1):  # 洗牌算法,生成一个新列表,其元素为输入列表元素的顺序打乱版
    list2=[]
    list2=list1.copy()
    n = len(list2)
    for i in range(n - 1, 0, -1): 
        # 从前i+1个元素中随机选择一个元素
        j = rd.randint(0, i)
        # 交换当前位置的元素和随机选择的元素
        list2[i], list2[j] = list2[j], list2[i]
    return list2

Names = ['Bob','Tom','Alice','Jerry','Wendy','Smith','Leanerd']

print(Names) # ['Bob', 'Tom', 'Alice', 'Jerry', 'Wendy', 'Smith', 'Leanerd']
print(shuffle(Names)) # ['Smith', 'Wendy', 'Alice', 'Bob', 'Tom', 'Leanerd', 'Jerry']
# 调用自建shuffle函数,生成一个新列表将原列表元素顺序打乱,是有返回值的函数,调用后其本身为一个值
print(Names) # ['Bob', 'Tom', 'Alice', 'Jerry', 'Wendy', 'Smith', 'Leanerd']
# 自建shuffle函数显然没有对原列表产生影响
rd.shuffle(Names) # 调用random.shuffle()函数,是一个没有返回值的函数
print(Names) # ['Wendy', 'Leanerd', 'Alice', 'Smith', 'Bob', 'Jerry', 'Tom']
# 可以发现random.shuffle函数对原列表的元素顺序产生了影响
print(rd.shuffle(Names)) # None
# 这个函数没有返回值,作为语句产生作用,但返回值为None
print(Names) # ['Alice', 'Wendy', 'Jerry', 'Bob', 'Smith', 'Leanerd', 'Tom']
# 可以看到这个函数出现在print的参数中也会产生作用,只是没有返回值

6.3 参数

6.3.1 参数传递

在python中,变量是没有类型的,它仅仅是一个对象的引用,也就是作为一个指针指向某个类型的对象
在第4部分数据类型中,我们介绍了可变数据和不可变数据
简单回顾如下

  • 不可变数据:Number 数字、 String 字符串、Tuple 元组 不可修改其中数据
  • 可变数据:List 列表、Dictionary 字典、Set 集合 可修改其中数据

在python函数的参数传递中,

  • 如果将不可变的对象传入函数,只是将其指向的值传入函数,没有影响对象本身,也就是在函数内部生成一个值相同的新对象
  • 如果将可变的对象传入函数,则是将该对象真正传入函数,对该对象进行修改,在函数外部的对象也会受到影响,上面的对列表洗牌的例子就是这样

6.3.2 参数类型

调用函数时可使用的正式参数类型有:

  1. 位置函数(Positional Arguments)
    位置参数是在函数定义中必须提供值的参数,并且必须以正确的顺序传入参数,调用时的数量必须与声明时的一样,
    而且通常来说位置参数必须在调用或声明时处于前面的位置
def greet(name, greeting, punctuation):
    message = f"{greeting}, {name}{punctuation}"
    return message

result = greet('Alice', 'Hi', '!!!') # Hi, Alice!!!
print(result)

如果输入顺序错误或没有提供值,就会导致输出错误或直接报错

def greet(name, greeting, punctuation):
    message = f"{greeting}, {name}{punctuation}"
    return message

result = greet('Alice', '!!!', 'Hi')
print(result) # !!!, AliceHi
# 由于顺序错误导致输出语义错误
  1. 关键字参数(Keyword Arguments)
    关键字参数与函数的调用关系紧密,关键字参数也需要在调用时提供值,但是不同的是在调用时通过对参数名进行指定其值,可以在其调用时交换参数的顺序,但是调用时关键字参数必须位于位置参数后面
def greet(name, greeting, punctuation):
    message = f"{greeting}, {name}{punctuation}"
    return message

result = greet('Alice', punctuation='!!!', greeting='Hi') 
print(result) # Hi, Alice!!!
# 这里name是位置参数,后两个是关键字参数,可以看到通过对其参数名进行指定可以交换后两个参数位置而不会使输出语义产生歧义

但是在如下的程序中声明函数时顺序为name greeting punctuation,而调用时中间参数greeting作为关键字参数而punctuation作为位置参数就会发生错误,此时以按照位置顺序将’!!!'赋给greeting,导致greeting的值过多,所以要注意在声明处注意位置参数的顺序,下面的程序可以将声明中greeting与punctuation位置交换来解决错误

def greet(name, greeting, punctuation):
    message = f"{greeting}, {name}{punctuation}"
    return message

result = greet('Alice', '!!!', greeting='Hi') # 发生异常: TypeError keyword argument
print(result)
  1. 默认参数(Default Arguments)
    默认参数是在声明时已经给定了默认值的参数,所以在调用时可以不传入值,此时就会直接使用默认值
def greet(name, greeting, punctuation='!'):
    message = f"{greeting}, {name}{punctuation}"
    return message

result = greet('Alice', 'Hi') # Hi, Alice!
print(result)
# 这里在声明时就默认punctuation参数值为'!',故不传入参数就会使用默认值
  1. 可变位置参数(Arbitrary Positional Arguments)
    在声明函数时,某些位置参数的数量是不确定的,所以就需要可变位置参数,这种参数以元组的形式传递给函数,在声明时用*来表示
def greet(*args):
    message = ''
    for arg in args:
        message += arg
    return message

result = greet('Hi', ', ', 'Alice', '!!!')
print(result) # Hi, Alice!!!
  1. 可变关键字参数(Arbitrary Keyword Arguments)
    与可变位置参数类似,某些关键字参数的数量是不确定的,引入可变关键字参数,这种参数以字典的形式传递给函数,在声明时用**来表示
def info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

info(name='XYZ', age=22, school='HIT')
# ame: XYZ
# age: 22
# school: HIT
  • 注:在函数定义中,一般的顺序是:位置参数、可变位置参数、默认参数、关键字参数、可变关键字参数。
def example_function(arg1, arg2, *args, arg3='default_value', kwarg1=None, kwarg2=None, **kwargs):
    # 函数体
    pass

example_function(1, 2, 3, 4, kwarg1='value1', kwarg2='value2', extra_arg='extra_value')

在这个例子中

arg1 被赋值为 1
arg2 被赋值为 2
*args 被赋值为 (3, 4)
arg3 没有提供值,因此使用默认值 'default_value'
kwarg1 被赋值为 'value1'
kwarg2 被赋值为 'value2'
**kwargs 被赋值为 {'extra_arg': 'extra_value'}
  1. 强制位置参数
    Python3.8 新增了一个函数形参语法/用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。
def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)
# 形参 a 和 b 必须使用指定位置参数,c 或 d 可以是位置形参或关键字形参,而 e 和 f 要求为关键字形参

6.4 lambda函数(匿名函数)

lambda 函数是一种小型、匿名的、内联函数,它可以具有任意数量的参数,但只能有一个表达式。
这种函数不需要def关键字来定义,只需要使用lambda来创建,用来编写单行的简单函数
如同它的名字一样,lambda函数没有函数名,通常作为参数传递给其他函数来使用

格式:
lambda 参数: 单句表达式
lambda函数可以包含零个或多个参数,但必须在冒号前指定

比如上面的程序就可定义为:

f = lambda a, b, /, c, d, *, e, f :print(a, b, c, d, e, f)

6.5 函数装饰器

函数装饰器是一个函数,接收一个函数作为输入,返回一个函数作为输出,一般以@进行调用。
基本语法:

@decorator
def func():
  # 函数体

等价于

def func():
  # 函数体

func = decorator(func)

以一个程序来说明:

def greet(func):
    def addinfo():
        print("Hello,", end=' ')
        func()
    return addinfo

@greet
def greetx():
    print("World!")

greetx() # Hello, World!

可以看到装饰器@greet接收func为输入,addinfo为输出,这里addinfo后并未加(),因为一旦加上括号,那么就表示调用了该函数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HIT-Zxy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值