# 函数
函数是执行某一任务的一段代码,通过将一段代码定义成函数,并指定函数名,在需要的时候通过函数名来调用这段代码,函数是代码复用的重要手段。
函数的定义形式如下:
def 函数名(形参列表):
[return [返回值]]
#样例如下:
def findMax(x,y):
'''
获取两个数中比较大的那个数
findMax(x,y)
x,y为要比较的两个数
'''
return x if x > y else y
print(findMax(1,2))
help(findMax)
print(findMax.__doc__)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
上面提供了函数的说明文档,这样使用help时就能查看它的用法,这样有助于理解长时间没有使用的函数。当函数有多个返回值时会返回一个元组:
def getValue(a,b):
return a,b
print(getValue(1,2)[1])
2
3
4
# 递归函数
在一个函数体内调用自身,就称为函数递归,递归思想是解决不了当前问题时,去尝试解决跟他有关系的更简化的问题,直到能解决的问题,这个过程需要递推公式来不断的递归到能解决的问题:
def sum(n):
if n==1 :
return 1
else:
return sum(n-1)+n
print(sum(6))
2
3
4
5
6
7
# 函数参数
Python的函数参数可以为函数提供输入数据,这样函数根据不同的输入来运行。
按照形参位置来传入参数被称为位置参数,按照参数名来传入参数则是关键字(keyword)参数,使用关键字参数可以不管形参定义时的顺序,可以混用关键字参数和位置参数,但是混用时关键字参数必须在位置参数后面。
定义形参时,可以为形参指定默认值,但是指定了默认值的形参必须在没有默认值的参数后面。看下面示例:
def getArea(name,width=1,height=2):
print("name: %s,width: %i,height: %i" % (name,width,height))
return width*height
getArea("square1")
getArea("square1",10)
getArea("square1",height=20)
2
3
4
5
6
7
Python的参数个数可以是不确定的,这就是可变形参,可变形参都会被放入到一个元组中,也可以放到一个字典中:
def getBookList(author,*books,num=10):
for book in books:
print(book)
print("author %s,nubmer: %s" %(author,num))
getBookList("li","chinese","math","english",20)
getBookList("li","chinese","math","english",num=20)
def varInput(a,b,c=3,*inputTuple,**inputDict):
print(a,b,c)
print(inputTuple)
print(inputDict)
varInput(1,2,"test1","test2",ke1="test3",ke2="test4")
varInput(1,2,ke1="test3",ke2="test4")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Python中还有逆向参数收集的概念,指的是程序在已有列表,元组,字典等对象的前提下把它们的元素拆开来传给函数参数。
def testList(name,num,*other):
print("name: %s,num: %s" %(name,num))
print(other)
#列表
list1=["li",10,"hi","world"]
testList(*list1)
#元组
tuple1=("wang",20,"hello","nice")
testList(*tuple1)
#字典
dict1={'num':30,'name':"sun"}
testList(**dict1)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 值传递
Python中形参的传递是值传递,即将变量的值传递给形参变量,而形参变量均为新开辟的变量。
def swap(a,b):
a,b=b,a
print("in swap function,a: %s,b %s" % (a,b))
a=1
b=2
swap(a,b)
print("in main,a: %s,b %s" % (a,b))
2
3
4
5
6
7
8
但是把列表或字典传给形参时,虽然依旧是值传递,但是这时传递的是变量地址,不是变量内容。
def swap(dict1):
dict1["a"],dict1["b"] = dict1["b"],dict1["a"]
dict1=None
print(dict1)
dict1={"a":1,"b":2}
swap(dict1)
print(dict1)
2
3
4
5
6
7
8
# 局部函数
前面的函数都是在全局范围内定义的,它们都是全局函数,Python支持在局部作用域中定义函数,这种函数被称为局部函数。
默认情况下,局部函数对全局作用域是隐藏的,局部函数只在局部作用域内有效。注意如果封闭函数返回它的局部函数,这个局部函数被保存在一个变量中,这些局部作用域的函数就会被扩大:
def sealedFunc():
num=100
def getNum():
num=101
def setNum():
nonlocal num
num=102
setNum()
print(num)
getNum()
print(num)
return getNum
sealedFunc()
2
3
4
5
6
7
8
9
10
11
12
13
14
# 函数变量
Python中的函数也可以看成是一种值,所有函数都是function对象,可以把一个函数赋给一个变量,就像一个整数一样:
def addFunc(a,b):
return a+b
def multiFunc(a,b):
return a*b
def operTwoNumber(a,b,func):
return func(a,b)
print(operTwoNumber(2,3,multiFunc))
print(operTwoNumber(2,3,addFunc))
2
3
4
5
6
7
8
9
10
# Lambda表达式
由于上面的局部函数定义完之后,对外部是不可见的,它的函数名在内部使用又有限,此时可以使用Lambda表达式,它的本质是匿名的,单行函数体的函数。相对于单行函数体,它省去了定义函数的过程,让代码更简洁,另外对于不需要多次复用的函数,lambda表达式可以在用完之后立即释放,提高了性能。
def getFunc(typeinfo):
if typeinfo=="add":
return lambda a,b:a+b
if typeinfo=="multi":
return lambda a,b:a*b
print(getFunc("multi")(2,3))
map1 = map(lambda x : x if x % 2 == 0 else None,range(10))
print(list(map1))
# 下面两种形式也是等价的:
def func(x):
return x+100
list(map(func,range(10)))
## 等价于
list(map(lambda x:x+100,range(10)))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 变量作用域
在Python中,变量分为两种:
- 局部变量:在函数中定义的变量,包括参数。
- 全局变量:在函数外面定义的变量。
每个函数执行时都会,系统会给函数分配一块"临时内存空间",所有的局部变量都被保存在这块临时内存空间中,当函数执行完,这块临时内存空间就被释放,局部变量也都因释放而失效。全局变量意味着它们可以在所有的函数中被访问。
全局变量,局部变量会各被存储在一个字典中,要输出相应的字典,可以使用这三个工具函数:
- globals():返回全局范围所有变量。
- locals():返回当前范围的所有变量,如果在全局范围内使用这个函数,也会返回全局范围内的所有变量。
- vars(object):返回指定对象范围内的所有变量,如果不传入object参数,它的作用同locals()。
- nonlocal:返回外部嵌套函数内的变量,不是局部变量,也不是全局变量。
注意:
- locals()和globals()获取全局范围内的变量字典时,是可以修改的并且可以影响全局变量。但是locals()来获取局部范围内的变量字典时,即使修改,也不会影响局部变量。
var=100
def testScope():
localVar=1000
locals()["localVar"]=888
print("locals in testScope:%s" % locals())
print("globals in testScope:%s" % globals())
testScope()
locals()["var"]=999
print("locals:%s" % locals())
globals()["var"]=1000
print("globals:%s" % globals())
print("vars:%s" % vars())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
注意如果在局部作用域引用过全局作用域的变量,此时局部作用域中再使用该变量就会报错:
var=100
def testScope():
print(var)
var=1000
print(var)
testScope()
print(var)
2
3
4
5
6
7
8
如果将testScope中的第一行print语句注释掉,就不会报错,程序会在testScope中新建一个局部变量,然后输出该变量。要解决这个问题,有两种方式,一是使用globals()来访问var中的内容:
var=100
def testScope():
print(globals()["var"])
var=1000
print(var)
testScope()
print(var)
2
3
4
5
6
7
8
另一种是直接将该变量指定为是对全局变量的引用:
var=100
def testScope():
global var
var=1000
print(var)
testScope()
print(var)
2
3
4
5
6
7
8
最后是获取外部函数的变量:
num1 = 1
def test():
num1 = 2
def test1():
nonlocal num1
num1 = 3
test1()
print("in test: %s",num1)
test()
print("int global:%s",num1)
2
3
4
5
6
7
8
9
10
11
# 闭包函数
闭包是能够读取其他函数内部变量的函数,一般是函数内部的子函数,在子函数中,包含外层函数定义的变量(不是在子函数且不是在全局上下文),它的意义:
- 保护函数内的变量安全,要访问函数内的变量,只有通过闭包访问。
- 在内存中持久化一个变量,该变量会一直在内存中,不像函数的局部变量,运行完就释放。
来看实例:
def tester(start):
def nested(label):
print(label,nested.state)
nested.state +=1
nested.state = start
return nested
F = tester(1)
F('hello')
F('world')
F('this')
F('is')
F('future')
2
3
4
5
6
7
8
9
10
11
12
13