前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >day12- 函数

day12- 函数

作者头像
似小陈吖
发布2024-04-03 08:46:49
710
发布2024-04-03 08:46:49
举报
文章被收录于专栏:测试那些事测试那些事

我们学习编程的时候,一学到函数就感觉很难,其实函数很简单,听我给你细细道来,在我们之前的学习中,我们最常用的一个操作,打印输出print(),其实这就是我们最先接触的函数,只不过这是由Python源码中编写好的函数,那我们来看下print()函数到底是怎么写的?

从中我们可以看到用到def关键字,然后接一个print还有一个括号并且里边有内容,这样我们就可以使用print打印输出这个功能了,下边我们详细介绍函数

1、什么是函数

1、为什么有函数

函数是组织好的,可重复使用的,用来实现单一、或相关联功能的代码段。这句话怎么理解,比如我们要比较2和3的大小,我们可以直接写

代码语言:javascript
复制
num1 = 2
num2 = 3
if num1 < num2:
    print("2小于3")
else:
    print("2大于3")

那如何我们下次又要比较5和6的大小呢,把代码可以在写一遍,如果下次再比较10和11的大小呢,这时候就可以用到函数

2、函数的定义

我们一般使用 def 关键词作为声明,后面紧接着是函数标识符名称与圆括号 (),最后接一个冒号 :

代码语言:javascript
复制
def 函数名(参数列表):
    # 函数体
    return [返回值]

函数体 必须有缩进,在函数体我们编写要实现的功能逻辑

  • 函数名:见名识意,通俗点,不建议使用单字母
  • 参数列表:设置该函数可以接收多少个参数,多个参数之间用逗号( , )分隔(也可不带参数,但是括号不能省略)
  • return [返回值] :返回该函数的返回值。可以有返回值也可以没有

小栗子

熟悉招式后,我们就可以练习,在我们上边还有一个问题,比较两个数的大小,可能有很多两个数,我们用函数实现

代码语言:javascript
复制
# 定义比较两个数字的函数
def compare_numbers(num1, num2):
    # 如果num1小于num2
    if num1 < num2:   
        # 打印num1小于num2
        print("{}小于{}".format(num1, num2))
    # 否则
    else:
        # 打印num1大于num2
        print("{}大于{}".format(num1, num2))

这样我们就写好了这个函数

3、函数的调用

调用函数是什么意思,我们不是把函数都写好了吗,我们来执行上边的代码,比较两个数大小的函数

发现执行结果为空

现在懂了吧,函数相当于我们的工具,可以是扳手,也可以是螺丝刀,如果没有手使用,就会毫无效果

所以我们得调用函数,才能使用函数的功能,来看下调用:

语法格式如下所示:

代码语言:javascript
复制
函数名(参数)    # 第一种调用方式,如果有参数就填写对应参数,无参数可以不写
返回值 = 函数名(参数)    # 第二种调用方式,如果函数有返回值,得变量来接收该值

括号里传的参数需要额外注意,定义函数的时候有几个参数,调用的时候就传几个参数,并且要保持顺序

在我们小栗子中,我们来调用一下

代码语言:javascript
复制
compare_numbers(2, 3)
compare_numbers(6, 5)
compare_numbers(10, 11)


# 执行结果
2小于3
6大于5
10小于11

看,这样以后我们不管在比较多少次两个数的大小,就不需要在编写重复的代码了

在我们实际编程工作中,如果不是单一功能的代码,也可以不用使用函数,这个要看情况使用

2、函数的参数

1、函数的值传递和引用传递

函数中有形参和实参,我们拿一个具体例子,传入一个数字,返回这个数字的2倍数字

代码语言:javascript
复制
def toal(num):
    return num * 2

在我们定义的函数中,num就是我们的形参,相当于放个位置,不做实际使用

我们调用上边的函数

代码语言:javascript
复制
toal(5)

我们调用函数,括号中实际传入5,这就是我们的实参,函数实际会拿实参来进行逻辑处理

好,我们理解了形参和实参后,就来看下我们的值传递和引用传递:

  1. 值传递:适用于实参类型为不可变类型(字符串、数字、元组)
  2. 引用(地址)传递:适用于实参类型为可变类型(列表,字典)

那值传递和引用传递有什么区别啊?

值传递,形参的值发生改变,不影响实参的值 引用传递,改变形参的值,实参的值也会一同改变

我们来做个例子参考下:

代码语言:javascript
复制
# 定义了一个函数
def change(a):
    a += 100  
    print("函数内:", a)
    
a = 100
change(a)
print("函数外:", a)

猜猜看,函数内的值是多少,函数外的值是多少

执行结果:

代码语言:javascript
复制
函数内: 200
函数外: 100

大家猜的准吗

这个就属于值传递,虽然形参里的改变了,但是实际我们定义的实际参数值虽然在函数中进行了改变,但是实际的值是不会改变的

当然这种适用于数字,字符串,元祖等不可变类型

那引用传递是什么呢?

代码语言:javascript
复制
# 函数的引用传递
def f(a):
    a[0] = 100
    print('函数内:', a)

a = [1, 2, 3, 4]
f(a)
print('函数外:', a)

执行结果:

代码语言:javascript
复制
函数内: [100, 2, 3, 4]
函数外: [100, 2, 3, 4]

这下大家应该都猜对了吧,引用传递,传递给函数参数是实际引用地址,修改形参中的值后,引用地址就会改变,所以传递给实参的值也会进行改变

2、位置参数

位置参数,也叫必传参数,顾名思义,参数是必须要传入的,并且还要按照位置顺序传入,如果没有按照上边要求,会报错或者得到结果不一致

直接看例子

代码语言:javascript
复制
def hello(name, message):
    print(f"{name}! {message}")

传入1个参数

代码语言:javascript
复制
hello("小华")

# 执行结果
TypeError: hello() missing 1 required positional argument: 'message'

传入3个参数

代码语言:javascript
复制
hello("小华", '你好', '哈哈')

# 执行结果
TypeError: hello() takes 2 positional arguments but 3 were given

传入2个参数

代码语言:javascript
复制
hello("小华", '你好')
hello("你好", '小华')

# 执行结果
小华! 你好
你好! 小华

所以,在调用函数时,一定要确定好位置

3、默认参数

默认参数,函数定义时,如果给某个参数提供一个默认值,这个参数就变成了默认参数

直接看代码:

代码语言:javascript
复制
def hello(name='小华', message):
    pass
 
 def hello(message,name='小华'):
    pass

上述两个代码有问题吗,在编辑器中发现第一个函数报错了

原因就在默认参数必须在位置参数后面!

那默认值参数有什么用呢?

默认值参数表示这个参数就算不给传参,也有一个默认值,不会报错

代码语言:javascript
复制
def test1(a, b=1):
    print(a, b)
    

test1(0)
test1(0, 2)

执行结果

代码语言:javascript
复制
0 1
0 2

代码是没问题的

实战练习

Python编程题

代码语言:javascript
复制
# 默认参数传空列表
def my_function(a=[]):
    a.append('A')
    print(a)


my_function()
my_function()
my_function()

不实际运行代码,答案是什么?

那不很简单吗

代码语言:javascript
复制
['A']
['A']
['A']

如果是这个答案,肯定错误

真正的答案是:

代码语言:javascript
复制
['A']
['A', 'A']
['A', 'A', 'A']

默认参数传入空列表,在我们函数的引用传递中我们知道,如果参数传入的是列表,表示传入的参数的引用地址,而后边列表改变了,默认参数表示这个默认值也对应改变了,所以调用一次函数后续再次调用这个函数的参数的默认值就会改变

4、可变参数

可变参数也叫动态参数,为什么有可变参数呢

比如我们有求2个数的求和函数

代码语言:javascript
复制
def add(a, b):
    return a + b

之后又需要3个数的求和函数

代码语言:javascript
复制
def add(a, b,c):
    return a + b + c

那之后,我们要求100个数的和,应该怎么做呢

这时候就用到了我们的动态参数

Python的动态参数有两种,分别是*args**kwargs,这里面的关键是一个和两个星号的区别

至于叫*a或者*as是没有区别的,只不过Python官方默认让我们使用这个*args**kwargs

*args

定义中使用星号 * 来表示。它允许函数接受任意数量的位置参数,并将它们作为一个元组传递给函数

代码语言:javascript
复制
# 函数可变参数
def my_func(*args):
    for arg in args:
        print(arg)


my_func('hello', 'world', 123)

打印结果

代码语言:javascript
复制
hello
world
123

如果传入的是一个列表呢

代码语言:javascript
复制
def my_func(*args):
    for arg in args:
        print(arg)


my_func([1, 2, 3, 4])

猜猜打印的结果是什么

正确答案:[1, 2, 3, 4]

为什么不是1,2,3,4分别打印出来呢,因为当传入的参数为列表,是作为一个整体传入的,那接受会用一个元祖接受就是args = ([1, 2, 3, 4],),遍历元祖整个列表表示为1个元素会打印输出

那如果我们想要1,2,3,4作为单独的元素一个个传入给参数呢,我们可以用解包操作符 * 来将列表的元素作为独立的参数传递给函数

代码语言:javascript
复制
my_func(*[1, 2, 3, 4])

再来看看打印结果

代码语言:javascript
复制
1
2
3
4

如果可变参数和位置参数和默认参数联合使用呢,看下边这个例子:

代码语言:javascript
复制
def myfun(a, *b, c=None):
    print(a)
    print(b)
    print(c)
myfun(1, 2, 3, 4)

猜猜a,b,c各自的值,执行结果:

代码语言:javascript
复制
1
(2, 3, 4)
None

a拿到了1,b作为可变参数,把后边的值都接受了,所以c没有拿到值

所以,我们如果想要给c赋值,我们就要指定参数值,这就用到了我们的关键字参数

5、关键字参数

我们在调用函数时,可以以 “参数名 = 参数值” 的形式传递参数,这种我们可以认为强行赋值,不需要传递,所以不受位置影响,还是上边的例子,我们要给c赋值,这时候我们就用关键字参数

代码语言:javascript
复制
def myfun(a, *b, c=None):
    print(a)
    print(b)
    print(c)
myfun(1, 2, 3, c=4)

# 执行结果
1
(2, 3)
4

那如果我们把给c赋值放在最前面可以吗?

代码语言:javascript
复制
myfun(c=4, 2, 3)

# 执行结果
 myfun(c=4, 2, 3)
               ^
SyntaxError: positional argument follows keyword argument

代码报错了,因为如果有关键字参数,调用的时候顺序必须放在最后面

代码语言:javascript
复制
myfun(2, 3,c=4)

6、可变关键字参数

**kwargs

定义中使用星号 ** 来表示,它允许函数接受任意数量的键值对也就是关键字参数,并将它们作为一个字典传递给函数

代码语言:javascript
复制
# 函数可变参数
def my_func(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")


my_func(name="小华", age=25, city="beijing")

打印结果

代码语言:javascript
复制
name: 小华
age: 25
city: beijing

这是第一种传递方式:key=value 的方式传参

如果我们传入整个字典,是否可以?

代码语言:javascript
复制
# 函数可变参数
def my_func(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

my_dict = {
    "name": "小华",
    "age": 25,
    "city": "beijing"
}
my_func(my_dict)

执行结果:报错

这是因为,我们传入整个字典,属于位置参数传递方式,但是我们的函数没有任何位置参数,所以类型就会报错,如果我们想要以整个字典的方式传入,我们可以使用字典解包操作符 **,这样就可以将字典中的键值对分别作为关键字参数传递给函数。

7、参数的顺序

一个函数中包含多种参数的组合,必须遵守这样的顺序:位置参数(必传参数),默认参数,单星号参数,双星号参数

定义参数时,位置参数都必须在关键字参数之前

代码语言:javascript
复制
def my_func(a=1, b):
    print(a, b)
    
 # 这种写法就会报错,关键字参数必须放在位置参数后边

可变参数中,单星号要在双星号之前

代码语言:javascript
复制
def my_func(a, b, c=0, *args, **kwargs):
    print(a, b, c, args, kwargs)
    

my_func(1, 2, 3, 4, 5, x=9, y=10)
my_func(1, 2, x=9, y=10)
my_func(1, 2, 3, (4, 5), a=9, b=10)
my_func(1, 2, 3, x=9, y=10, z=11)
my_func(1, 2, 3, x=9, y=10, z=11, a=12)

不运行代码,猜猜结果

还有一个小细节,单星号后面的都是关键字参数,无论是否带=;

代码语言:javascript
复制
def my_func(a, b, c=0, *args, d , **kwargs):
    print(a, b, c, args,d, kwargs)

上述中的d在*args后面,因此属于关键字参数,虽然没有带=

3、函数的返回

1、返回是什么

Python函数,可以用 return 语句指定应该返回的值,该返回值可以是任意类型 语法格式:return [返回值]

2、返回有两个作用

  • 提前退出函数
  • 返回具体的数据
代码语言:javascript
复制
def add(a, b):
    return a + b
    print(a + b)


add(3, 4)

上述一个求和的代码,我们执行后会返回什么,试一试,发现返回的是啥也没有,为什么呢?我们的代码里不是有打印a+b吗,是的,但是执行到return的时候,就直接跳出函数了,所以return 语句会提前退出函数

那我们想看下我们返回的数据应该怎么办,有返回值的时候,我们可以将函数赋值给一个变量,变量保存函数的返回值,然后打印输出

代码语言:javascript
复制
num = add(3, 4)
print(num)

当然我们如果不需要返回,也可以不写return,这样就会默认返回None的

代码语言:javascript
复制
def add(a, b):
    a + b
num = add(3, 4)
print(num)

3、None是什么?

None 是一个特殊的常量,表示空或缺失,和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。

None 常用于 assert、判断以及函数无返回值的情况

4、return多个值

我们可以使用return返回多个值

代码语言:javascript
复制
def add(a, b):
    return a + b, a - b

上述函数返回两个数的和,和两个数的差,我们打印看一下:

代码语言:javascript
复制
print(add(5, 3))

# 执行结果
(8, 2)

return 多个返回值,得到的是一个元组,后续我们可以根据元祖取值

这里,我们也可以分别接受一下对应的值

代码语言:javascript
复制
he, cha = add(5, 3)
print('和:', he)
print('差:', cha)

day12练习

初级:

1.定义函数名add,接受两个数字参数,求和返回值

2.定义函数名Area,参数接受r半径的值,求圆的面积,(计算公式:π*r*r)

3.定义函数名season,接受一个月份参数,返回其对应的季节(春夏秋冬)

4.定义函数名reverse,接受一个字符串参数,并返回逆序后的字符串(比如传入abcdef,返回fedcba)

中级:

1.编写一个函数 find_max(numbers),接受一个整数列表 numbers,并返回列表中的最大值

2.编写一个函数 is_prime(n),判断一个正整数 n 是否为素数(质数)

3.编写一个函数 remove_list(numbers),接受一个整数列表 numbers,并移除列表中的重复元素,返回去重后的列表

高级

1.请写一个函数 equals ,该函数参数为任意数量的数字,请在函数中统计出这些参数数字中重复的数字有多少个

比如 :

代码语言:javascript
复制
equals(3, 4, 3, 4, 1, 6, 2) 

输出为:

代码语言:javascript
复制
数字 3 出现了 2 次
数字 4 出现了 2 次
数字 1 出现了 1 次
数字 6 出现了 1 次
数字 2 出现了 1 次
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、什么是函数
    • 1、为什么有函数
      • 2、函数的定义
        • 小栗子
          • 3、函数的调用
          • 2、函数的参数
            • 1、函数的值传递和引用传递
              • 2、位置参数
                • 3、默认参数
                  • 实战练习
                    • 4、可变参数
                      • *args
                    • 5、关键字参数
                      • 6、可变关键字参数
                        • **kwargs
                      • 7、参数的顺序
                      • 3、函数的返回
                        • 1、返回是什么
                          • 2、返回有两个作用
                            • 3、None是什么?
                              • 4、return多个值
                              • day12练习
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档