我们学习编程的时候,一学到函数就感觉很难,其实函数很简单,听我给你细细道来,在我们之前的学习中,我们最常用的一个操作,打印输出print()
,其实这就是我们最先接触的函数,只不过这是由Python源码中编写好的函数,那我们来看下print()函数到底是怎么写的?
1、什么是函数
1、为什么有函数
函数是组织好的,可重复使用的,用来实现单一、或相关联功能的代码段。这句话怎么理解,比如我们要比较2和3的大小,我们可以直接写num1 = 2 num2 = 3 if num1 < num2: print("2小于3") else: print("2大于3")那如何我们下次又要比较5和6的大小呢,把代码可以在写一遍,如果下次再比较10和11的大小呢,这时候就可以用到函数
2、函数的定义
我们一般使用def
关键词作为声明,后面紧接着是函数标识符名称与圆括号 ()
,最后接一个冒号 :
def 函数名(参数列表): # 函数体 return [返回值]
函数体
必须有缩进,在函数体我们编写要实现的功能逻辑
- 函数名:见名识意,通俗点,不建议使用单字母
- 参数列表:设置该函数可以接收多少个参数,多个参数之间用逗号( , )分隔(也可不带参数,但是括号不能省略)
- return [返回值] :返回该函数的返回值。可以有返回值也可以没有
小栗子
熟悉招式后,我们就可以练习,在我们上边还有一个问题,比较两个数的大小,可能有很多两个数,我们用函数实现# 定义比较两个数字的函数 def compare_numbers(num1, num2): # 如果num1小于num2 if num1 < num2: # 打印num1小于num2 print("{}小于{}".format(num1, num2)) # 否则 else: # 打印num1大于num2 print("{}大于{}".format(num1, num2))这样我们就写好了这个函数
3、函数的调用
调用函数是什么意思,我们不是把函数都写好了吗,我们来执行上边的代码,比较两个数大小的函数 发现执行结果为空
现在懂了吧,函数相当于我们的工具,可以是扳手,也可以是螺丝刀,如果没有手使用,就会毫无效果
所以我们得调用函数,才能使用函数的功能,来看下调用:
语法格式如下所示:
函数名(参数) # 第一种调用方式,如果有参数就填写对应参数,无参数可以不写 返回值 = 函数名(参数) # 第二种调用方式,如果函数有返回值,得变量来接收该值括号里传的参数需要额外注意,定义函数的时候有几个参数,调用的时候就传几个参数,并且要保持顺序 在我们小栗子中,我们来调用一下
compare_numbers(2, 3) compare_numbers(6, 5) compare_numbers(10, 11) # 执行结果 2小于3 6大于5 10小于11
看,这样以后我们不管在比较多少次两个数的大小,就不需要在编写重复的代码了 在我们实际编程工作中,如果不是单一功能的代码,也可以不用使用函数,这个要看情况使用
2、函数的参数
1、函数的值传递和引用传递
函数中有形参和实参,我们拿一个具体例子,传入一个数字,返回这个数字的2倍数字def toal(num): return num * 2在我们定义的函数中,num就是我们的形参,相当于放个位置,不做实际使用 我们调用上边的函数
toal(5)我们调用函数,括号中实际传入5,这就是我们的实参,函数实际会拿实参来进行逻辑处理 好,我们理解了形参和实参后,就来看下我们的值传递和引用传递:
那值传递和引用传递有什么区别啊?
- 值传递:适用于实参类型为不可变类型(字符串、数字、元组)
- 引用(地址)传递:适用于实参类型为可变类型(列表,字典)
值传递,形参的值发生改变,不影响实参的值 引用传递,改变形参的值,实参的值也会一同改变我们来做个例子参考下:
# 定义了一个函数 def change(a): a += 100 print("函数内:", a) a = 100 change(a) print("函数外:", a)猜猜看,函数内的值是多少,函数外的值是多少 执行结果:
函数内: 200 函数外: 100大家猜的准吗 这个就属于值传递,虽然形参里的改变了,但是实际我们定义的实际参数值虽然在函数中进行了改变,但是实际的值是不会改变的 当然这种适用于数字,字符串,元祖等不可变类型 那引用传递是什么呢?
# 函数的引用传递 def f(a): a[0] = 100 print('函数内:', a) a = [1, 2, 3, 4] f(a) print('函数外:', a)执行结果:
函数内: [100, 2, 3, 4] 函数外: [100, 2, 3, 4]这下大家应该都猜对了吧,引用传递,传递给函数参数是实际引用地址,修改形参中的值后,引用地址就会改变,所以传递给实参的值也会进行改变
2、位置参数
位置参数,也叫必传参数,顾名思义,参数是必须要传入的,并且还要按照位置顺序传入,如果没有按照上边要求,会报错或者得到结果不一致 直接看例子def hello(name, message): print(f"{name}! {message}")传入1个参数
hello("小华") # 执行结果 TypeError: hello() missing 1 required positional argument: 'message'传入3个参数
hello("小华", '你好', '哈哈') # 执行结果 TypeError: hello() takes 2 positional arguments but 3 were given传入2个参数
hello("小华", '你好') hello("你好", '小华') # 执行结果 小华! 你好 你好! 小华所以,在调用函数时,一定要确定好位置
3、默认参数
默认参数,函数定义时,如果给某个参数提供一个默认值,这个参数就变成了默认参数 直接看代码:def hello(name='小华', message): pass def hello(message,name='小华'): pass上述两个代码有问题吗,在编辑器中发现第一个函数报错了 原因就在默认参数必须在位置参数后面! 那默认值参数有什么用呢? 默认值参数表示这个参数就算不给传参,也有一个默认值,不会报错
def test1(a, b=1): print(a, b) test1(0) test1(0, 2)执行结果
0 1 0 2代码是没问题的
实战练习
Python编程题# 默认参数传空列表 def my_function(a=[]): a.append('A') print(a) my_function() my_function() my_function()不实际运行代码,答案是什么? 那不很简单吗
['A'] ['A'] ['A']如果是这个答案,肯定错误 真正的答案是:
['A'] ['A', 'A'] ['A', 'A', 'A']默认参数传入空列表,在我们函数的引用传递中我们知道,如果参数传入的是列表,表示传入的参数的引用地址,而后边列表改变了,默认参数表示这个默认值也对应改变了,所以调用一次函数后续再次调用这个函数的参数的默认值就会改变
4、可变参数
可变参数也叫动态参数,为什么有可变参数呢 比如我们有求2个数的求和函数def add(a, b): return a + b之后又需要3个数的求和函数
def add(a, b,c): return a + b + c那之后,我们要求100个数的和,应该怎么做呢 这时候就用到了我们的动态参数 Python的动态参数有两种,分别是
*args
和**kwargs
,这里面的关键是一个和两个星号的区别
至于叫*a或者*as是没有区别的,只不过Python官方默认让我们使用这个*args
和**kwargs
*args
定义中使用星号*
来表示。它允许函数接受任意数量的位置参数,并将它们作为一个元组传递给函数
# 函数可变参数 def my_func(*args): for arg in args: print(arg) my_func('hello', 'world', 123)打印结果
hello world 123如果传入的是一个列表呢
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作为单独的元素一个个传入给参数呢,我们可以用解包操作符 *
来将列表的元素作为独立的参数传递给函数
my_func(*[1, 2, 3, 4])再来看看打印结果
1 2 3 4如果可变参数和位置参数和默认参数联合使用呢,看下边这个例子:
def myfun(a, *b, c=None): print(a) print(b) print(c) myfun(1, 2, 3, 4)
猜猜a,b,c各自的值,执行结果:
1 (2, 3, 4) None
a拿到了1,b作为可变参数,把后边的值都接受了,所以c没有拿到值 所以,我们如果想要给c赋值,我们就要指定参数值,这就用到了我们的关键字参数
5、关键字参数
我们在调用函数时,可以以 “参数名 = 参数值” 的形式传递参数,这种我们可以认为强行赋值,不需要传递,所以不受位置影响,还是上边的例子,我们要给c赋值,这时候我们就用关键字参数def myfun(a, *b, c=None): print(a) print(b) print(c) myfun(1, 2, 3, c=4) # 执行结果 1 (2, 3) 4
那如果我们把给c赋值放在最前面可以吗?
myfun(c=4, 2, 3) # 执行结果 myfun(c=4, 2, 3) ^ SyntaxError: positional argument follows keyword argument
代码报错了,因为如果有关键字参数,调用的时候顺序必须放在最后面
myfun(2, 3,c=4)
6、可变关键字参数
**kwargs
定义中使用星号**
来表示,它允许函数接受任意数量的键值对也就是关键字参数,并将它们作为一个字典传递给函数
# 函数可变参数 def my_func(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}") my_func(name="小华", age=25, city="beijing")
打印结果
name: 小华 age: 25 city: beijing
这是第一种传递方式:key=value 的方式传参 如果我们传入整个字典,是否可以?
# 函数可变参数 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、参数的顺序
一个函数中包含多种参数的组合,必须遵守这样的顺序:位置参数(必传参数),默认参数,单星号参数,双星号参数 定义参数时,位置参数都必须在关键字参数之前def my_func(a=1, b): print(a, b) # 这种写法就会报错,关键字参数必须放在位置参数后边
可变参数中,单星号要在双星号之前
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)
不运行代码,猜猜结果 还有一个小细节,单星号后面的都是关键字参数,无论是否带=;
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、返回有两个作用
- 提前退出函数
- 返回具体的数据
def add(a, b): return a + b print(a + b) add(3, 4)
上述一个求和的代码,我们执行后会返回什么,试一试,发现返回的是啥也没有,为什么呢?我们的代码里不是有打印a+b吗,是的,但是执行到return的时候,就直接跳出函数了,所以return 语句会提前退出函数 那我们想看下我们返回的数据应该怎么办,有返回值的时候,我们可以将函数赋值给一个变量,变量保存函数的返回值,然后打印输出
num = add(3, 4) print(num)
当然我们如果不需要返回,也可以不写return,这样就会默认返回None的
def add(a, b): a + b num = add(3, 4) print(num)
3、None是什么?
None
是一个特殊的常量,表示空或缺失,和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。
None 常用于 assert、判断以及函数无返回值的情况
4、return多个值
我们可以使用return返回多个值def add(a, b): return a + b, a - b
上述函数返回两个数的和,和两个数的差,我们打印看一下:
print(add(5, 3)) # 执行结果 (8, 2)return 多个返回值,得到的是一个元组,后续我们可以根据元祖取值 这里,我们也可以分别接受一下对应的值
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 ,该函数参数为任意数量的数字,请在函数中统计出这些参数数字中重复的数字有多少个
比如 :
equals(3, 4, 3, 4, 1, 6, 2)
输出为:
数字 3 出现了 2 次 数字 4 出现了 2 次 数字 1 出现了 1 次 数字 6 出现了 1 次 数字 2 出现了 1 次
标签:函数,参数,day12,print,my,我们,def From: https://www.cnblogs.com/nuomituan/p/18111267