Python的函数
1、定义
1)函数,数学定义 y=f(x) y是x的函数,x是自变量。
2)Python函数:
3)由若干语句组成的语句块,函数名称,参数列表,组织代码的最小参数。完成一定的功能。
2、函数的作用
结构化编程对代码的最基本的封装,一般按照功能组织一段代码。
封装的目的是为了复用,减少冗余代码。
代码更加简洁美丽、可读易懂。
3、函数分类
内建函数:max()
库函数:math() ceil()等
4、函数的定义、调用
def语句定义函数:
def 函数名(参数列表):
函数体(代码块)
[return 返回值]*
函数名就是标示符,命名要求一样。
语句块必须缩进,约定四个空格
Python的函数没有return语句,隐式会返回一个none值。
定义中的参数列表成为形式参数,只是一种符号表达,简称形参。
调用:函数定义,只是声明了一个函数,他不会被执行,需要调用。
调用方式,就是函数名加上小括号,括号内写上参数。
调用时候的参数就是实际参数,是实实在在的传入的值,称为实参。
定义的时候叫做形参。
调用的时候叫做实参。
def add(x,y):
result = x+y
return result
out = add(4,5)
print(out)
函数是可调用的对象,利用callable()查询。
调用通过函数名add加两个参数,返回值可使用变量接收。
计算的结果,通过返回值进行返回。
必须加同类型的。复用的。
定义需要在调用前,也就是说调用的时候已经被定义过了,否则会抛出异常的。
def add(x,y):
result = x+y
return result
out = add('a','b')
print(out)
5、函数的参数
1)参数调用时传入的参数要和定义的个数匹配(可变参数除外)。
位置参数
2)def f(x,y)调用时使用 f(1,3)
按照参数的定义位置顺序传入实参。
3) 关键字参数def(x,y,z)调用使用f(x=1,y=3,z=5)
使用形参的名字来出入实参的方式,使用了形参的名字,顺序可以定义的顺序不一。
4)传参
f(z=none,y=10,x=[1])
f((1,) z=6,y=4.1 )
要求位置参数必须在关键字参数之前,位置参数的按照位置对应的。
位置在前 关键字在后。
6、函数参数默认值
add()可以使用 默认使用缺省值。
参数默认值(缺省值)
定义时,在形参后跟上一个值
def add(x=4, y=5):
return x+y
测试调用 add(6, 10) 、add(6, y=7) 、add(x=5) 、add()、add(y=7)、 {add(x=5, 6) 、add(y=8,4)不可以的类型。}型}
add(x=5, y=6)、add(y=5, x=6)
测试定义后面这样的函数 def add(x=4,y)定义的时候也是不可以的。
作用:参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值
参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用
7、函数参数默认值:
#代码例子
def login(host='192.168.133.128',port='8888',username='wcl',password='wwww'):
print('{}:{}@{}/{}'.format(host, port, username, password))
login()
login('127.0.0.1', 80, 'wcl', 'wcl')
login('127.0.0.1', username='root')
login('localhost', port=80,password='com')
login(port=80, password='wcl', host='www')
#打印出来的
192.168.133.128:8888@wcl/wwww
127.0.0.1:80@wcl/wcl
127.0.0.1:8888@root/wwww
localhost:80@wcl/com
www:80@wcl/wcl
最常用的,常见的参数放在前面。
缺省值往往都会使用。
8、可变参数
问题:有多个数没需要累加求和。
def add(nums):
传入的参数是一个,可以是列表,集合或者是元组。
#代码例子
def add(nums):
sum = 0
for i in nums:
sum+=i
return sum
add([1,2,3])
#例子
def add(nums):
sum = 0
for i in nums:
sum+=i
return sum
add((1,2,3))
1)可变参数:
一个形参可以匹配任意个参数。
位置参数的可变参数:
有多个数,在形参前面使用*标示该形参是可变参数,可以接收多个实参。
收集多个实参为一个tuple
没有return的返回的是一个值none。
#代码示例
def add(*nums):
sum =0
for i in nums:
sum +=i
print(sum)
add(3,5,6)
14
2)关键字参数的可变参数
形参前使用**符号,表示可以接手多个关键字参数。
收集 的实参名称和值组成一个字典。
不带*号的往前放,*号多的放后面。
#代码例子
def showconfig(**kwargs):
for k,v in kwargs.items():
print('{}={}'.format(k,v))
showconfig(host='192.168.133.128',port='8888',usrname='root',passeord='wwww')
#打印出的结果;
host=192.168.133.128
passeord=wwww
usrname=root
port=8888
#位置参数和关键字参数混合
def showconfig(nsername,*args,**kwsrgs):
#def showconfig(x,y,*args,**kwargs):
print(x)
print(y)
print(args)
print(kwargs)
showconfig(3,4,6,7,8,a=1,b='python')
#打印
3
4
(6, 7, 8)
{'b': 'python', 'a': 1}
9、可变参数的总结
有位置可变参数和关键字可变参数。
位置参数在可变参数的形参前面使用一个*。
关键字可变参数在形参前面使用两个**。
位置可变参数和关键字,都可以收集如干个实参,位置参数收集形成一个tuple 关键字参数收集形成一个dict。
混合使用参数的时候,可变参数要放到参数列表的最后,普通参数需要放到参数列表前面,位置可变参数需要在关键字可变参数
10、keyword-only参数
如果在一个星号参数后,或者一个位置可变参数后,出现的普通参数,实际上已经不是普通的参数了,而是keyword-only参数.
#例子
def fn(*args,x):
print(x)
print(args)
fn(3,5,x=7)
11、*号
def fn(*,x,y)
*号之后,普通形参都(变成了关键字参数,不在是位置参数了)。都必须给出keyword-noly。
只有可变的才可以给0个,不可变对的必须给定其值。
12、def可变参数和默认值
#例子
def fn(*args,x=5):
print(x)
print(args)
fn(1,12,4,x=3)
13、参数规则
参数列表参数一般顺序是:普通参数、缺省参数,可变位置参数,keyword-only参数(可带缺省值),可变关键字参数。
#代码示例
def fn(x,y,z=3,*arg,m=4,n,**kwargs):
print(x,y,z,m,n)
print(args)
print(kwargs)
fn(1,2,n=3)
14、参数解构
不仅可以解构数据类型,还可以解构可迭代对象。
给函数提供实参的时候,可以在集合类型前面使用*或者**。
非字典类型使用*
字典类型使用**
提出出来的元素数目要和形参需要的参数一致。
#代码练习
def add(x,y,*args):
return x+y
add(*[1,2,3,4,5])
#代码练习
def add(x,y,*args):
return x+y
add(**{'x':3,'y':5})
#结构字典
d1={'x':3,'y':5}
def add(x,y,*args):
return x+y
add(*d1.keys())
#结构字典
d1={'x':3,'y':5}
def add(x,y,*args):
return x+y
add(*d1.values())
传参时候的方式,
结构,配参。
15、函数的返回值及作用域
里面包含隐式转换。
return只会返回一个。
ruturn 语句的本质也是打断。
#def showplus(x):
print(x)
return x+1
showplus(5)
print会执行语句。
#def showplus(x):
print(x)
return x+1
print(x+1)
后面的print不会执行,遇到return其实就是打断。相当于break。
#def showplus(x):
print(x)7
return x+1
return x+2
只有一个返回语句,第一个返回就相当于被打断。
1)总结
使用return语句返回“返回值”
所有函数都有返回值,如果没有return返回语句,返回的是none.
Return 并一定是函数语句块的最后一条语句。
一个函数存在多个return语句,但是只一条可以被执行。没有return语句,返回的none
如果有必要,可以显示调用return none,可以简写为return。
如果函数执行了return语句,函数就会返回返回值,后面的语句就不会被执行。
作用:结束函数调用,返回值。
2)函数的返回值
#def showlist():
return [1,3,5]
返回多个值
函数不能同时返回多个值,return[1,3,5]是指明返回一个列表,是一个列表对象。
return1,3,5看似是多个值,但是隐士的被封装了。
#def showlist():
return 1,3,5
#(1, 3, 5)
x,y,z=shoulist()使用结构提取更方便。
16、函数的嵌套。
1)函数内可以定义函数
#def f1():
def f2():
print('f2')
print('f1')
f2()
f1()
#调用f2()的时候就会报错,因为f2()是在内层函数中定义的。
函数有可见范围,这就是作用域概念。
内部函数不能直接被外部使用,会抛出nameError异常。
17、作用域***
函数内在函数外是找不到的。
外部在内部是可见的。
1)概念
:一个标示符的可见范围,这就是标示符的作用域,一般指的是变量的作用范围。
2)全局作用域:在整个程序运行环境中都可见。globl
3)局部作用域:在函数、类等内部可见。局部变量使用范围内不能超过其所在的局部作用域。local.
#def fn1():
x=1
def fn2():
print(x)
fn2()
fn1()
#def f3():
o=65
def f4():
print('f4:{}'.format(o))
print(chr(o))
print('f3:{}'.format(o))
f4()
f3()
#out:
f3:65
f4:65
A
内部函数o使用外层函数定义的o的值。
#def f3():
o=65
def f4():
o=97
print('f4:{}'.format(o))
print(chr(o))
print('f3:{}'.format(o))
f4()
f3()
#f3:65
f4:97
a
赋值即定义。
#
x=5
def foo():
x+=1
print(x)
foo()
本地变量x没有被定义,就拿出使用,本地的x只是空的值。
#
x=5
def foo():
y=x+1
print(y)
foo()
本地可以,因为这样的利用的全局变量x。
在小环境中必须重新进行定义的。
18、全局变量global
#例子
x=5
def foo():
global x
x+=1
print(x)
foo()
使用global关键字的变量,将foo内的x声明为使用外部的全局作用域。
#x=5
def foo():
global x
x=10
x+=1
print(x)
foo()
利用global把x定义为了全局变量,但是内部函数在定义x=10是没有作用的。
内部作用域使用x=5之类的赋值语句会重新定义局部变量x。如果利用global 把x一旦声明为全局变量,那么x=5相当于为全局作用域赋值。
global总结
x+=1这种特殊的形式产生错误的原因,先引用后赋值,python是赋值才算定义。才能被引用。
global的使用原则:基本不使用。
外部作用域变量会内部作用域可见,但是也不要在这个内部的局部作用域内直接使用,因为函数的目的就是为了封装。
如果需要外部全局变量,使用函数传参的方式。
19、闭包
1)自由变量:未在本地作用域中定义的变量,例如定义在内层函数外的外层函数的作用域中的变量。
2)闭包:就是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的的自由变量,就是形成了闭包。(内层函数用到了外层函数的自由变量)
#def f1():
c = [0](是一个自由变量)
def f2():
c[0] +=1
return c[0]
return f2
f=f1()
print(f(),f())
print(f())
Python3中可以使用nonlocal来实现闭包
global只是在声明的和最外部的作用。
使用global可以解决,但是这种使用的是全局变量,而不是闭包。
20、nonlocal
使用了nonlocal关键字,将变量标记在上级的局部作用域中定义,但不能是全局作用域中.定义。
#def counter():
count=0
def inc():
nonlocal count (利用nonlocal)
count +=1
return count
return inc
foo = counter()
foo()
foo()
Count是外层函数的局部变量,被内存函数引用。
内部函数使用nonlocal关键字声明变量count在上级作用域中而非在本地中定义。
代码可以运行,并形成闭包。
nonlocal不是全局作用域中的。
21、默认值作用域
#def foo(xyz=[]):
xyz.append(1)
print(xyz)
foo()
foo()
Print(xyz)#只会报错,因为未定义变量xyz。xyz只是本地变量。
属性,多次打印的数值会变化。
#例子题
def foo (xyz=1):
print(xyz)
foo()
foo()
print(xyz)
Print(xyz)#只会报错,因为未定义变量xyz。xyz只是本地变量。
函数也是对象,调用的时候时候也是执行一次对象,也只是一份。
为什么第二次打印是list中元素增加呢?
因为函数也是对象,把函数的默认值放在了属性中,这个属性就伴随着这个函数对象整个生命周期。 查看属性:foo.__defaults__
函数的地址并没有改变,就是说函数的对象没有变,调用它,他的属性利用元素来保存所有的默认值。xyz只是默认值的引用类型,引用类型的元素变动,而不是整个元组变动。
#例子。
def foo(xyz=[],u='abc',z=123):
xyz.append(1)
return xyz
print(foo(),id(foo))
print(foo.__defaults__)
print(foo(),id(foo))
print(foo.__defaults__)
#out
[1] 140682069694800
([1], 'abc', 123)
[1, 1] 140682069694800
([1, 1], 'abc', 123)
属性__defaults__中使用元组保存所有位置参数默认值,他不会因为在函数体内使用了他而发生改变。
#例题
def foo(w,u='abc',*,z=123,zz=[456]):
u='xyz'
z=789
zz.append(1)
print(w,u,z,zz)
print(foo.__defaults__)
foo('magedu')
print(foo.__defaults__)
属性__defaults__中使用元组保存所有位置参数默认值。
属性__kwdefaults__中使用字典保存所有keyword-noly参数的默认值。
默认值的作用域
使用可变类型作为默认值,就可以修改这个值。
有些时候有用,有些时候特性不好,有副作用。
改变的话有两种方法。
1)改变特性的两个方式。
第一种方法:使用影子拷贝创建一个新的对象,永远不能改变传入的参数。
函数体内,不改变默认值。
xyz都是传入参数或者默认参数的副本,如就想修改参数,无能为力。
#例题:
def foo (xyz=[],u='abc',z=123):
xyz = xyz[:]
xyz.append(1)
print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo()
foo([10])
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)
第二种方法:通过值得判断就可以灵活的选择创建或者修改传入的对象。(最常用)
很多函数 的定义,都可以看到使用None这个不可变的值作为默认参数,一种惯用方式。
使用不可变类型的默认值
如果使用缺省值None就创建一个列表
如果传入一个列表,就修改这个列表。
#例题
def fn(xyz=None,u='abc',z=123):
if xyz is None:
xyz=[]
xyz.append(1)
return xyz
lst = fn()
a=fn(lst)
print(a)
#输出结果
[1, 1]
None
22、函数的销毁(引用计数减一)
1) 全局函数销毁
重新定义同名函数
Del语句删除函数对象
程序结束时
#例题
def foo(xyz=[],u='abc',z=123):
xyz.append(1)
return xyz
print(foo(),id(foo),foo.__defaults__)
def foo(xyz=[],u='abc',z=123):
xyz.append(1)
return xyz
print(foo(),id(foo),foo.__defaults__)
del foo
print(foo(),id(foo),foo.__defaults__)
2) 局部函数销毁
重新在上级作用域中进行定义同名函数。
del删除语句删除函数对象
上级作用域销毁时。
#试题:
def foo(xyz=[],u='abc',z=123):
xyz.append(1)
def inner(a=10):
pass
print(inner)
def inner(a=100):
print(xyz)
print(inner)
return inner
bar=foo()
print(id(foo),id(bar),foo.__defaults__,bar.__defaults__)
del bar
print(id(foo),id(bar),foo.__defaults__,bar.__defaults__)
浙公网安备 33010602011771号