1.函数
函数也是一个对象,就是我们在内存当中所开辟的一块区域,通过一些代码块实现特定的功能 。
可以用来保存一些可执行的代码,并且可以在需要的时候,对这些代码(语句)进行多次调用。
- 内置函数
- 自定义函数
1.1函数的定义
函数名必须按照标识符的命名规范
(可以包含字母 数字 下划线 但是不能以数字开头)
语法:
def 函数名([形参1,形参2...]):
代码块
注:函数中保存的代码块不会立即执行,需要调用函数代码才会执行
def fn():
print('这个是我第一个函数')
print('哈哈哈')
print('同学们好')
print('又到了周末')
print(fn)
<function fn at 0x00000000003D1E18>
此时打印出来的是一个函数所在的内存地址
fn是函数对象 fn() 调用函数
1.2函数的调用
函数对象()
2函数的参数
先看一个例子
def fn2(a,b):
print('a =',a)
print('b =', b)
print(a,'+',b,'=',a+b)
fn2(2,3)
fn2(222,666)
- 1在定义函数的时候,可以在函数后面的括号定义不等的形参
- 多个形参我们用 , 隔开
- 形参(形式参数) 定义形参就相当于在函数内部声明了变量,但是不是赋值
- 2 实参(实际参数) 指定了形参,那么你在调用函数的时候必须传递实际参数
- 实际参数将会赋值给对应的形参,就是你有几个形参就需要传递几个实参
2.1函数的参数传递方式
默认值
定义形参的时候,可以给形参指定默认值,指定了默认值之后,
如果用户传递了实参默认值不会发挥任何作用,如果用户没有传递,则默认值会发挥作用
观看以下例子
def fn(a,b,c=20):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn(1,2,3)
输出结果为:
a = 1
b = 2
c = 3
此结果符合:如果用户传递了实参默认值不会发挥任何作用 此结论
def fn(a,b,c=20):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn(1,2)
输出结果为:
a = 1
b = 2
c = 20
此结果符合:如果用户没有传递,则默认值会发挥作用
2.1.1函数实参的传递方式
- 位置传递
位置参数就是将对应位置的实参赋值给对应位置的形参.
第一个实参赋值给第一个形参,第二个实参赋值给第二个形参...
- 关键字参数
关键字参数,可以不按照形参定义的顺序去传递,而根据参数名去传递
如系统内置的一些,print('111',end='')
def fn(a = 5,b = 10,c = 20):
print('a =',a)
print('b =',b)
print('c =',c)
fn(b=1,c=2,a=5)
- 位置参数和关键字参数可以混合使用
混合使用的时候关键字和位置参数时,必须将位置参数写到关键字参数前面
def fn(a = 5,b = 10,c = 20):
print('a =',a)
print('b =',b)
print('c =',c)
fn(1,c=8)
2.1.2函数实参的类型
实参可以传递任意类型的对象
但是如果当一个函数中当出现数据相加,但是传递的参数当中有字符串时,虽然ide不会报错,但是实际函数执行的时候会报错,我们可以通过异常处理机制进行处理
def fn2(a):
print('a =', a)
# b = 123
# b = 'python'
# b = None
# b = False
# fn2(b)
# fn2(fn) 传递一个函数,指向的是这个函数的内存地址
- 我们看下面一个例子
def fn4(a):
a = 20
a[0] = 50
print('a =',a,id(a))
c = 10
fn4(c)
执行结果如下:
a = 20 1548185664
c= 10
通过上面的结果们可以看出:
在函数中对形参进行重新赋值,不会影响其他的变量
- 再看一个例子
def fn4(a):
a[0] = 50
print('a= ',a,id(a))
c = [1,2,3]
fn4(c)
print('c= ',c,id(c))
执行结果为:
a= [50, 2, 3] 2591199028936
c= [50, 2, 3] 2591199028936
通过结果我看可以看出此参数c传递后,形参a和c指向的是同一个对象,所以在内部修改相应的元素,c也会变
- 再看下面的例子
def fn4(a):
a[0] = 50
print('a= ',a,id(a))
c = [1,2,3]
fn4(c.copy())
print('c= ',c,id(c))
执行结果为:
a= [50, 2, 3] 2757291878344
c= [1, 2, 3] 2757289404104
由上面的结果我们可以得出:
如果你在传递的是一个可变对象的时候,而你又不希望我在函数内部的操作影响到函数外部的时候。那么你就可以考虑传递一个对象的副本,通过对象.copy()的方式将其复制一份
2.2函数的不定长参数
其实就是将多余的参数放进一个包里
(*a处理位置参数 **a处理的是关键字参数)
在定义函数时,可以在形参前边加上一个*,这样做的好处是这个形参可以获取到所有的实参.
它将会把所有的实参保存到一个元组当中
先看一段代码:
#定义一个函数,求任意个数的和
def sum(a,b,c):
print(a,b,c)
sum(1,2,3)
此时当我们想传起过3个数的时候,程序会报错,这个时候我们可以使用不定长参数来解决
我们可以将上面的代码改写成下面这样:
def sum(*a):
# 定义一个变量 用来保存的结果
result = 0
# 遍历元祖,并将元祖中的数进行计算
for n in a:
result = result + n
print(result)
sum(12,45,46,55,20)
执行结果为:178
===================================================================
不定长参数也可以和其他参数配合使用
不定长参数不是必须写在最后,但是要注意,带*的参数后面的所有参数,必须以关键字的参数形式传递
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
===================================================================
** 形参可以接受其他的关键字参数,它会将这些参数统一保存到一个字典当中
自定的key就是关键字的名字,字典的value就是参数的值
**形参只能有一个 并且必须写在所有参数后面
def fn3(b,c,**a):
print('a =', a)
print('b =', b)
print('c =', c)
fn3(b=1,d=2,c=3,e=5,f=20)
执行结果为:
a = {'d': 2, 'e': 5, 'f': 20}
b = 1
c = 3
2.3函数参数的解包
*param 解包
我们先看一下下面的代码:
def fn4(a,b,c):
print('a =', a)
print('b =', b)
print('c =', c)
t=(1,2,3)
fn4(t)
此时执行程序会直接报错
我们把程序稍做调整:
def fn4(a,b,c):
print('a =', a)
print('b =', b)
print('c =', c)
t=(1,2,3)
fn4(t[0],t[1],t[2])
上面的方法虽然能解决,但是这只是参数少的情况下,如果我有100个,1000个的时候会写死人的,所以上面的方法并不合适,我们需要把元组赋值给形参
我们根据之前学的方法,可以在序列类型的参数前添加*,这样它会自动将序列当中的元素依次作为参数传递,这里要求序列当中的元素的个数必须和形参的个数保持一致
代码如下:
def fn4(a,b,c):
print('a =', a)
print('b =', b)
print('c =', c)
t=(1,2,3)
fn4(*t)
执行结果:
a = 1
b = 2
c = 3
上面的这种将序列参数拆开进行传递方式就被称之解包
**param 解包
这种方式用于将字典类型的参数进行解包,因为之前我们在封包的时候通过 param,可以将多余的参数解析为一个字典,但是要注意把字典当参数进行解包时,字典当中的key必须是以关键字的参数传递方式才行
def fn4(a,b,c):
print('a =', a)
print('b =', b)
print('c =', c)
t={'a':1,'b':2,'c':3}
fn4(**t)
执行结果:
a = 1
b = 2
c = 3
网友评论