Python6 - 函数总结
一、函数的基本知识
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
1.1函数定义规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
1.2语法格式:
def 函数名(参数列表): 函数体
1.3函数的参数:
- 默认参数
- 位置参数
- 关键参数
- 非固定参数 *args 和 **kwargs
默认参数:
调用函数时,如果没有传递参数,则会使用默认参数。
#可写函数说明 def printinfo( name, age = 35 ): "打印任何传入的字符串" print ("名字: ", name); print ("年龄: ", age); return; #调用printinfo函数 printinfo( age=50, name="runoob" ); print ("------------------------") printinfo( name="runoob" );
位置参数:
注意: 位置参数的顺序不可变。
关键字参数:
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
def printme( str ): "打印任何传入的字符串" print (str); return; #调用printme函数 printme( str = "菜鸟教程");
关键字参数的使用不需要指定顺序
#可写函数说明 def printinfo( name, age ): "打印任何传入的字符串" print ("名字: ", name); print ("年龄: ", age); return; #调用printinfo函数 printinfo( age=50, name="runoob" );
非固定参数:
非固定参数或者不定长参数,上述3种参数不同,声明时不会命名,基本语法:
def functionname([formal_args,] *var_args_tuple ): "函数_文档字符串" function_suite return [expression]
加了星号(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。
# 可写函数说明 def printinfo( arg1, *vartuple ): "打印任何传入的参数" print ("输出: ") print (arg1) for var in vartuple: print (var) return; # 调用printinfo 函数 printinfo( 10 ); printinfo( 70, 60, 50 );
需要注意:
- 关键参数必须放在位置参数之后。
- *args 会把多传入的位置参数变成一个元组(tuple)形式
- *kwargs 会把多传入的关键参数变成一个字典dict形式
1.4全局与局部变量:
- 对于数字和字符串来说在函数内部默认是不能更改全局变量的
- 如果非要在函数内硬改全局变量,需要在函数内添加 global 函数名,具体见下面global实例1
- 但是这种做法并不推荐
myname = "Rong" def change_name(): global myname #不推荐,不要用 myname = "TanRong" change_name() print(myname)
names_list = ["Jack","Tom","xiaohong"] info_dict = {"name": "Jack", "age":18, "sex":"女"} def change_name(): # global myname # myname = "TanRong" names_list[0] = "xiaoming" info_dict["age"] = 20 change_name() # print(myname) print(names_list) print(info_dict) 输出: ['xiaoming', 'Tom', 'xiaohong'] {'name': 'Jack', 'age': 20, 'sex': '女'}
1.5返回值:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
二、特殊函数
2.1递归函数:
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
def calc(n): print(n) if int(n/2) ==0: return n return calc(int(n/2)) calc(10) 输出: 10 5 2 1
递归特性:
1. 必须有一个明确的结束条件,, 默认深度好像是999
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
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: #find it print("找到数字",dataset[mid]) elif dataset[mid] > find_num :# 找的数在mid左面 print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid]) return binary_search(dataset[0:mid], find_num) else:# 找的数在mid右面 print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid]) return binary_search(dataset[mid+1:],find_num) else: if dataset[0] == find_num: #find it print("找到数字啦",dataset[0]) else: print("没的分了,要找的数字[%s]不在列表里" % find_num) binary_search(data,66)
2.2嵌套函数:
顾名思义,函数内定义并调用函数
name = "Tan" def change_name(): name = "Tan2" def change_name2(): name = "Tan3" print("第3层打印", name) change_name2() # 调用内层函数 print("第2层打印", name) change_name() print("最外层打印", name)
修改嵌套作用域:
要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了
def outer(): myage = 118 def inner(): nonlocal myage # nonlocal关键字声明 myage = 126 print(myage) inner() print(myage) outer() 输出: 126 126
2.3匿名函数:
python 使用 lambda 来创建匿名函数。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
- lambda 只是一个表达式,函数体比 def 简单很多。
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
语法如下:
lambda [arg1 [,arg2,.....argn]]:expression
sum = lambda a,b: a + b print(sum(30,50))
res = map(lambda x:x**2, [1,2,3,4,5]) for i in res: print(i) 输出: 1 4 9 16 25
2.4高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
def add(x,y,f): return f(x) + f(y) res = add(3,-6,abs) print(res)
2.5内置函数
详解:https://docs.python.org/3/library/functions.html?highlight=built#ascii
#compile f = open("函数递归.py") data =compile(f.read(),'','exec') exec(data) #print msg = "又回到最初的起点" f = open("tofile","w") print(msg,"记忆中你青涩的脸",sep="|",end="",file=f) # #slice # a = range(20) # pattern = slice(3,8,2) # for i in a[pattern]: #等于a[3:8:2] # print(i) # # #memoryview #usage: #>>> memoryview(b'abcd') #<memory at 0x104069648> #在进行切片并赋值数据时,不需要重新copy原列表数据,可以直接映射原数据内存, import time for n in (100000, 200000, 300000, 400000): data = b'x'*n start = time.time() b = data while b: b = b[1:] print('bytes', n, time.time()-start) for n in (100000, 200000, 300000, 400000): data = b'x'*n start = time.time() b = memoryview(data) while b: b = b[1:] print('memoryview', n, time.time()-start)