文章目录
一、函数
- 数就是将一段具有独立功能的代码块 整合到一个整体并命名,在需要的位置调用这个名称即可完成对应的需求。
函数在开发过程中,可以更高效的实现代码重用。
二、函数的定义与调用
在python中 ,函数是一个组织好的 ,可以重复使用的代码段 ,函数可以提高代码的重复利用率 ,原则上一个函数只实现一个单一的功能 ,这样能增强程序的模块性, python有许多的内置函数可供你使用, 你也可以自己定义函数,这通常被称之为自定义函数
2.1 函数的定义
函数也是一个对象,函数的对象是function,被<>包裹的就是一个对象。
def 函数名(参数列表):
函数体
函数名是一个函数对象,函数名()调用函数。
先看几个示例
def fn():
pass
def fn(a):
pass
def fn(a, b, c):
pass
关于上面这段代码,你要记住下面3个结论
- 函数可以没有参数
- 函数的参数可以是一个,也可以是多个
- pass的作用相当于占位符,没有实际作用
2.2 函数的调用
函数名(参数)
注意:
- 不同的需求,参数可有可无。
- 在Python中,函数必须先定义后使用。
- 示例1, 定义并调用没有参数的函数
def fn():
print('hello world')
fn() # hello world
- 示例2, 定义并调用有一个参数的函数
def fn(a):
"""
输出菱形
"""
for i in range(a):
if i <=a//2:
print(" "*(a//2-i) + "*"*(2*i + 1))
else:
print(" "*(i - a//2) + "*"*((a-i)*2-1))
fn(11)
'''
输出:
*
***
*****
*******
*********
***********
*********
*******
*****
***
*
'''
- 示例3, 定义并调用有三个参数的函数
def fn(a, b, c):
max_number = a
if b > max_number:
max_number = b
if c > max_number:
max_number = c
return max_number
max_num = fn(22, 23, 21)
print(max_num)
- 当你使用def 定义了一个函数后,只有调用这个函数才能让这个函数运行。
三、函数的参数
函数的参数这部分内容的很复杂,很重要。
3.1 形参和实参
- 函数的参数
-
在定义函数的时候,可以在函数名后面的括号中定义数量不等的形参。
-
定义多个形参要用逗号隔开。
-
所谓形参,就是函数定义中的参数,就是相当于在函数内部声明了变量,不是赋值,形参在函数体内可以使用。
-
实参(实际参数) 如果函数定义的时候指定了形参,那么在调用的时候也必须传递实参。
-
实参将会赋值给对应的形参,简单来说,有几个形参就得几个实参。
-
定义形参的时候,可以为形参指定默认值,指定了默认值以后,如果用户传递了参数则默认值没有任何作用,如果用户没有传递,则默认值会生效。
-
实参可以传递任意类型的对象,调用函数的时候,解析器是不会检查实参的类型。
-
位置参数和关键字参数可以混合使用,但是关键字产生不能放到位置参数的前面。
def fn(a):
for i in range(a):
if i <= a//2:
print(" "*(a//2-i) + "*"*(2*i + 1))
else:
print(" "*(i - a//2) + "*"*((a-i)*2-1))
fn(11)
- 上面的代码中,函数定义中的a就是形参,而最后一行的代码中,11就是实参,形参代表一种形式,实参,是实际的具体的起作用的数据。
def fn(a):
print('a=',a)
b =123 # 123
b = Ture # Ture
b = 'abc' # abc
fn(b)
- 实参可以传递任意类型的对象
3.2 必传参数(位置参数)
位置参数:调用函数时根据函数定义的参数位置来传递参数。
def user_info(name, age, gender):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')
user_info('TOM', 20, '男')
注意:传递和定义参数的顺序及个数必须一致。
def fn(a, b):
for i in range(b):
print(a)
fn('ok', 2)
- 上面定义的fn函数里有两个参数,a 和b,他们都是必传参数,在调用函数时,你必须传入两个值,否则就会报错,下面演示一种错误的调用方法
def fn(a, bt):
for i in range(b):
print(a)
fn('ok')
- 报错内容为
Traceback (most recent call last):
File "/Users/kwsy/kwsy/coolpython/test.py", line 5, in <module>
fn('ok')
TypeError: fn() missing 1 required positional argument: 'count'
- 从最后的TypeError的内容来看,缺失了一个位置参数(positional argument),我想,必传参数更能准确的描述这个参数的性质。 在函数fn内部,用到了b这个形参,可是调用函数时,只传了a, 却没有传b,最终报错。
def fn(a):
a = 20
print('a=',a)
c = 10
fn(c) # a= 20
print('c=',c) # c= 10
在函数中重新给形参赋值,不会影响其他的变量。
def fn(a):
a[0]= 20
print('a=',a,id(a))
c = [10,20,30,40]
fn(c) # a = [30, 20, 30] 3036669602560
print('c=',c,id(c)) # c = [30, 20, 30] 3036669602560
如果现在的形参执行的是一个对象,当我们通过形参去修改对象时,会影响到所有指向该对象的变量
def fn(a):
a[0]= 20
print('a=',a,id(a))
c = [10,20,30,40]
# fn(c.copy()) # a= [20, 20, 30, 40] 1623071716352
# print('c=',c,id(c)) # c= [10, 20, 30, 40] 1623071714048
fn(c[:]) # a= [20, 20, 30, 40] 2947320509440
print('c=',c,id(c)) # c= [10, 20, 30, 40] 2947320507136
3.3 默认参数
- fn函数根据b参数输出指定次数的a,我希望在两次输出的空档可以暂停一段时间,因此增加一个sleep参数
import time
def fn(a, b, sleep=1):
for i in range(b):
print(a)
time.sleep(1)
fn('ok', 2)
- 在调用函数时,我并没有传sleep这个形参,程序并没有报错,这是因为在定义函数的时候,给了sleep形参默认值1,这意味着,如果调用函数时没有传这个参数,python会用默认值来执行函数。默认值参数非常用有用,假设你在系统里的很多地方都使用最开始定义的fn函数
def fn(a, b):
pass
-
开始某一天,你需要增加一个参数sleep, 如果你将sleep定义为必传参数,那么所有用到函数fn的地方都必须修改调用时的代码来增加这个入参,但如果你把sleep定义为默认参数,sleep已经默认等于1,除非必须传入其他的数值,否则就不需要这么做,之前的代码仍然可以使用。
-
定义函数是时,如果有多个默认参数,他们必须放置在参数列表的最后,不允许在中间放置一个必传参数。
3.4 关键字参数
关键字参数不是一个出现在函数定义时的概念,而是一个出现在函数调用时的概念。
import time
def fn(a, b, sleep=1):
for i in range(b):
print(a)
time.sleep(1)
fn(bt=2, a='关键字参数', sleep=2)
-
在调用函数时,使用key=value的形式来传递参数,不仅如此,还打乱了顺序,先传入了b,后传入了a,关键字参数允许你以任何顺序传递参数,只要必传参数都以key=value的形式传值即可。现在,对于关键字参数是出现在函数调用时的概念应该有了清楚的概念。
-
使用关键字参数,可以让参数传递更加明确,让调用方清楚的知道每个参数的传值情况。
3.5 不定长参数(可变参数)
-
不定长参数分为两种:
-
*args 接受任意多个实际参数
-
**kwargs接收任意多个以关键字参数赋值的实际参数
-
3.5.1 *args
在定义函数时,有时候你并不希望参数的个数是固定的,这种设计在实际工作中很常见。
def fn(*args):
print(args, type(args))
sum_res = 0
for item in args:
sum_res += item
return sum_res
print(fn(2))
print(fn(2, 3, 4))
-
你可以看到,我在定义fn时,使用args, args只是个名字,也可以直接写成a,你可以随意修改,关键是前面有一个星。有了这个星,函数调用时传递多少个参数就变成了一个很随意的事情,所有传入的参数将被放入到一个元组中,因此args的类型是tuple元组。但是带*的形参只能有一个,可以配合其他参数使用。
-
*形参只能接受位置参数,不能接受关键字参数。
def fn2(a,b,*c):
print('a =',a)
print('b =',b)
print('c =',c)
fn2(1,2,3,4,5)
'''
a = 1
b = 2
c = (3, 4, 5)
'''
def fn2(a,*b,c):
print('a =',a)
print('b =',b)
print('c =',c)
fn2(1,2,3,4,c = 5)
'''
a = 1
b = (2, 3, 4)
c = 5
'''
def fn2(*a,b,c):
print('a =',a)
print('b =',b)
print('c =',c)
fn2(1,2,3,b = 4,c = 5)
'''
a = (1, 2, 3)
b = 4
c = 5
'''
不定长参数不一定非要写在后面,但是要注意,带*号后面的参数,都必须以关键字参数的形式来进行传递
3.5.2 **kwargs
def fn(**kwargs):
print(kwargs, type(kwargs))
for course, score in kwargs.items():
print(course, score)
fn(yuwen=89, shuxue=94)
-
在调用函数时,以关键字参数的形式进行参数传递,最终这些key-value对将组装成字典,kwargs的类型是dict。个人理解,kwargs就是一种为了偷懒而做的设计,当函数需要传入很多参数(多达10几个)时,使用kwargs定义函数是非常方便的。
-
**形参只能有一个,并且只能写在所有参数的后面
def fn4(b,c,**a):
print('a =',a)
print('b =',b)
print('c =',c)
fn4(b=1,d=2,c=3,e=10,f=50)
'''
a = {'d': 2, 'e': 10, 'f': 50}
b = 1
c = 3
'''
四、拆包和交换变量值
4.1 拆包
- 拆包:元组
def return_num():
return 100, 200
num1, num2 = return_num()
print(num1) # 100
print(num2) # 200
- 拆包:字典
dict1 = {'name': 'TOM', 'age': 18}
a, b = dict1
# 对字典进行拆包,取出来的是字典的key
print(a) # name
print(b) # age
print(dict1[a]) # TOM
print(dict1[b]) # 18
4.2 交换变量值
需求:有变量a = 10
和b = 20
,交换两个变量的值。
- 方法一
借助第三变量存储数据。
a = 10
b = 20
# 1. 定义中间变量
c = 0
# 2. 将a的数据存储到c
c = a
# 3. 将b的数据20赋值到a,此时a = 20
a = b
# 4. 将之前c的数据10赋值到b,此时b = 10
b = c
print(a) # 20
print(b) # 10
- 方法二
a, b = 1, 2
a, b = b, a
print(a) # 2
print(b) # 1
五、引用
5.1 了解引用
在python中,值是靠引用来传递来的。
我们可以用id()
来判断两个变量是否为同一个值的引用。 我们可以将id值理解为那块内存的地址标识。
# 1. int类型
a = 1
b = a
print(b) # 1
print(id(a)) # 140708464157520
print(id(b)) # 140708464157520
a = 2
print(b) # 1,说明int类型为不可变类型
print(id(a)) # 140708464157552,此时得到是的数据2的内存地址
print(id(b)) # 140708464157520
# 2. 列表
aa = [10, 20]
bb = aa
print(id(aa)) # 2325297783432
print(id(bb)) # 2325297783432
aa.append(30)
print(bb) # [10, 20, 30], 列表为可变类型
print(id(aa)) # 2325297783432
print(id(bb)) # 2325297783432
5.2 引用当做实参
代码如下:
def test1(a):
print(a)
print(id(a))
a += a
print(a)
print(id(a))
# int:计算前后id值不同
b = 100
test1(b)
# 列表:计算前后id值相同
c = [11, 22]
test1(c)
输出结果为:
100
140709393736448
200
140709393739648
[11, 22]
2831959059200
[11, 22, 11, 22]
2831959059200