函数
函数的定义
在某些语言中,函数声明和函数定义是分开的,但是在Python中,函数声明和函数定义是视为一体的。在Python中,函数定义的基本 形式如下:
def function(params): block return expression/value
(1)在Python中采用def关键字进行函数的定义,不用指定返回值的类型;
(2)函数参数params可以是零个,一个或者多个,同样的,函数参数也不用指定参数类型,因为在Python中变量都是弱类型的,Python会自动根据值来维护其类型;
(3)return语句是可选的,它可以在函数体内任何地方出现,表示函数调用执行到此结束;如果没有return语句,会自动返回None,如果有return语句,但是return后面没有接表达式或者值得话也是返回None。
例子:
def printhello(): print("Hello") print(printhello()) #执行结果: Hello None def printnum(): for i in range(0,10): print(i) return print(printnum()) #执行结果: None def add(a,b): return a+b print(add(1,2)) #执行结果: 3
函数的使用
在定义了函数之后,就可以使用函数了,但是在python中不允许前向引用,在函数定义之前,不允许调用该函数。
print(add(1,2)) def add(a,b): return a+b #执行结果 Traceback (most recent call last): File "C:UserswangzhigangDesktopatomtest.py", line 1, in <module> print(add(1,2)) NameError: name 'add' is not defined #提示函数没有定义
函数的参数
形参和实参
形参全程是形式参数,在用def关键字定义函数时函数名后面括号里的变量称作为形式参数。实参全称为实际参数,在调用函数时提供的值或者变量称作为实际参数。
def add(a,b): return a+b #这里的a和b为形参 add(1,2) x = 3 y = 5 #这里的1,2为实际参数 add(x,y) #这里的x,y是实参
参数的传递和改变
在python中,一切皆对象,变量中存放的是对象的引用。字符串,整型都是常量
print(id(5)) print(id("python")) x = 2 print(id(x)) y = 'Hello' print(id(y)) #执行结果: 1351637328 23420672 1351637280 23419520
id(函数)的官方解释:
id(obj, /) Return the identity of an object. This is guaranteed to be unique among simultaneously existing objects. (CPython uses the object's memory address.)
id(obj, /)函数是返回对象 obj在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。
例子:
x = 2 print(id(2)) print(id(x)) y = "Hello" print(id("Hello")) print(id(y)) #执行结果: 1351637280 1351637280 17324704 17324704
id(x)和id(2)的值是一样的,id(y)和id('hello')的值也是一样的。
在Python中一切皆对象,像2,'hello'这样的值都是对象,只不过2是一个整型对象,而'hello'是一个字符串对象。上面的x=2,在Python中实际的处理过程是这样的:先申请一段内存分配给一个整型对象来存储整型值2,然后让变量x去指向这个对象,实际上就是指向这段内存(这里有点和C语言中的指针类似)。而id(2)和id(x)的结果一样,说明id函数在作用于变量时,其返回的是变量指向的对象的地址。因为变量也是对象,所以在这里可以将x看成是对象2的一个引用。
变量的作用域:
在python中,也存在作用域。在python中,会为每个层次生成一个符号表,里层能调用外层中的变量,而外层不能调用里层的变量,并且当外层和里层有同名变量时,外层变量会被里层变量屏蔽掉。
def function(): x=2 count=2 while count>0: x = 3 print(x) count=count-1 print(count) function()
在函数function中,while循环外面和while循环里面都有变量x,此时,while循环外面的变量x会被屏蔽掉。注意在函数内部定义的变量作用域都仅限于函数内部,在函数外部是不能够调用的,一般称这种变量为局部变量。
还有一种变量:全局变量。它是在函数外部定义的,作用域是整个文件,全局变量可以直接在函数里面应用,但是如果要在函数内部改变全局变量,必须使用global关键字声明。
python函数参数的类型:
位置参数和关键字参数
位置参数:参数是通过位置进行匹配的,从左到右,依次进行匹配,这个对参数的位置和个数都有严格的要求。而在python中还有一种是通过参数名字来匹配的,这样就不需要严格按照参数定义的位置来传递参数,这种参数叫做关键字参数。
def display(a,b): print(a,b) #display("hello","world") #display("world") display("world","hello") #执行结果: hello world #报错 world hello
在Python中默认的是采用位置参数来传参。这样调用函数必须严格按照函数定义时的参数个数和位置来传参,否则会报错或者不是想要的结果。
def display(a,b): print(a,b) display(a="Hello",b="world") display(b="world",a="Hello") #执行结果: #执行结果是一样的,参数位置对结果没有影响 Hello world Hello world
关键字参数能够给函数参数提供默认值。
def display(a="hello",b="world"): print(a+b) display() display(b="world") display(a="hello") display("world") #执行结果: helloworld helloworld helloworld worldworld
分别给a和b指定了默认参数,即如果不给a或者b传递参数时,它们就分别采用默认值。在给参数指定了默认值后,如果传参时不指定参数名,则会从左到右依次进行传参,比如display('world')没有指定'world'是传递给a还是b,则默认从左向右匹配,即传递给a。
在重复调用函数时默认形参会继承之前一次调用结束之后该形参的值。
def insert(a,L=[]): L.append(a) print(L) insert("Hello") insert("world") #执行结果: ['Hello'] ['Hello', 'world']
任意个数参数
一般情况下,在定义函数时,函数参数的个数是确定的,但是某些情况下参数的个数不能确定,比如要存某个人的名字和他的小名,小名可能有多个,就无法确定参数的个数,可以使用收集函数,只需要再参数前面加上"*"或者''**"。
def storename(name,*nickName): print("real name is %s" % name) for nickname in nickName: print(nickname) storename("jack") storename("C.罗纳尔多","C罗") storename("C.罗纳尔多","C罗","罗总裁") #执行结果: real name is jack real name is C.罗纳尔多 C罗 real name is C.罗纳尔多 C罗 罗总裁
'*'和'**'表示能够接受0到任意多个参数,'*'表示将没有匹配的值都放在同一个元组中,'**'表示将没有匹配的值都放在一个dictionary中。
Python中函数是可以返回多个值的,如果返回多个值,会将多个值放在一个元组或者其他类型的集合中来返回。
递归函数
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
递归函数实例应用案例(1):
二分查找
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] def binary_search(dataset,find_num): print(dataset) if len(dataset) > 1: mid = int(len(dataset)/2) if dataset[mid] == find_num: print("找到数字",dataset[mid]) elif dataset[mid] > find_num: print("找的数在mid[%s]左边" % dataset[mid]) return binary_search(dataset[0:mid],find_num) else: print("找的数在mid[%s]右边" % dataset[mid]) return binary_search(dataset[mid+1:],find_num) else: if dataset[0] == find_num: print("找到数字啦",dataset[0]) else: print("不能分了,要找的数字[%s]不在列表中" % find_num) binary_search(data,35) #执行结果: [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] 找的数在mid[18]右边 [20, 21, 22, 23, 30, 32, 33, 35] 找的数在mid[30]右边 [32, 33, 35] 找的数在mid[33]右边 [35] 找到数字啦 35
递归函数案例(2):
def fact(n): if n == 1: return 1 return n * fact(n-1) print(fact(1)) print(fact(5)) #执行结果: 1 120
匿名函数
匿名函数用lambda关键字
一般应用在函数式编程中,对于一个列表,要求大于3的元素:
常规的方法:
L1 = [1,2,3,4,5] L2 = [] for i in L1: if i > 3: L2.append(i) print(L2) #执行结果: [4, 5]
匿名函数:
a = filter(lambda x:x>3,[1,2,3,4,5]) for i in a: print(i) #执行结果: 4 5