python开发基础----函数
python中函数定义:函数是逻辑结构化和过程化的一种编程方法,用来实现某一功能。(函数即变量,只有在调用的时候才会执行,没调用的时候,相当于把函数体当成字符串赋值给函数名)
python中函数定义方法:
def test(x):
"The function definitions"
x+=1
return x
def:定义函数的关键字
test:函数名
():内可定义形参
"":文档描述(非必要,但是强烈建议为你的函数添加描述信息)
x+=1:泛指代码块或程序处理逻辑
return:定义返回值
调用运行:可以带参数也可以不带
函数名()
使用函数的好处:
- 代码重用
- 保持一致性,易维护
- 可扩展性
函数和过程
过程定义:过程就是简单特殊没有返回值的函数
这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在python中有比较神奇的事情
总结:当一个函数/过程没有使用return显示的定义返回值时,python解释器会隐式的返回None,所以在python中即便是过程也可以算作函数。
- 如果没有返回值,则返回的是None
- 如果只有一个返回值,则返回的是object
- 如果有多个返回值,则返回的是一个元组(tuple)
函数的参数
1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定),如果混合使用,位置参数必须在关键字参数的左边
def test(x,y,z):
print(x)
print(y)
print(z)
#位置参数,必须一一对应,缺一不行多一也不行
test(1,2,3)
#关键字参数,无须一一对象,缺一不行多一也不行
test(x=3,y=2,z=5)
#位置参数和关键字参数混合使用,位置参数必须在关键字参数的左边
# test(1,y=3,4) #报错
# test(1,4,y=3) #报错
test(1,4,z=3)
4.默认参数,函数定义的时候就给参数默认赋值,调用函数时,可以不传这个参数的值,如果不传,就使用默认值,如果有传值,就用传进来的值
def test(x,type=None): #这里的type为默认参数
print(x)
print(type)
test(2)
test(2,5)
5.参数组(** 字典 、 * 列表),非固定长度的参数
def test(x,*args): # *args这个参数可以不传,不传就为空元组,相当于0或多个位置参数
print(x)
print(args)
test(1,2,3,4,5,6)
test(1) #*args这个参数可以不传,不传就为空元组
test(1,{'name':'alex'}) #如果直接传字典,会把字典当成一个元素传入*args保存到元组
test(1,['x','y','z']) #如果直接传列表,会把列表当成一个元素传入*args保存到元组,如果想把列表里的元素依次赋值给*args,可以用如下方式
test(1,*['x','y','z']) # *['x','y','z'] 相当于遍历列表之后再把列表中的每个元素传入
test(1,*{'name':'alex'}) #这里只会取字典的key值
结果
1
(2, 3, 4, 5, 6)
1
()
1
({'name': 'alex'},)
1
(['x', 'y', 'z'],)
1
('x', 'y', 'z')
1
('name',)
def test1(x,**kwargs): #相当于n个关键字参数
print(x)
print(kwargs)
test1(1,y=2,z=3)
# test1(1,2,3,4,5,y=2,z=3) #会报错,因为函数定义的位置参数只有1个
# test1(1,y=2,z=3,z=4) #会报错,一个参数不能传多次值
#如果两者需要结合到一起,应该位置参数在前面,关键字参数在后面,func test(*args,**kwargs): 如果要传入列表参数,要在参数前面加入* ,字典要用 **
局部变量与全局变量
- 在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
- 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
- 当全局变量与局部变量同名时:在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用
global关键字:指定全局变量
如果函数中有global关键字,变量本质上就是全局的那个变量,可读取可赋值
如果函数中没有global关键字,优先读取全局变量,无法对全局变量重新赋值,但是对于可变类型,可以对内部元素进行操作(如列表的append、pop等操作)
* 全局变量变量名全部大写
* 局部变量变量名全部小写
nonlocal 关键字 ,指定上一级变量
name='lhf'
def change_name():
print('我的名字',name)
change_name()
def change_name():
name='帅了一笔'
print('我的名字',name)
change_name()
print(name)
def change_name():
global name
name='帅了一笔'
print('我的名字',name)
change_name()
print(name)
函数递归调用
在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身
def test(x): print(x) if int(x/2) == 0: return x return x,test(int(x/2)) print(test(10)) 结果: 10 5 2 1 (10, (5, (2, 1)))
ls = ['alex','adqcsa','xieys','sb'] def ask_way(person_ls): if len(person_ls) == 0: return "没有人知道这个地方怎么走!" person = person_ls.pop(0) if person == 'xieys': return '%s说:这个地方在蛇口,做地铁在水湾站下!' % person print('hi,你好,%s ,请问网谷怎么走?' % person) print('%s说:我也不知道这个地方怎么走?我帮你问问别人%s.' % (person,person_ls)) res = ask_way(person_ls) print('%s说:%s'% (person,res)) return res ask_way(ls)
递归特性:
1. 必须有一个明确的结束条件
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, 20)
函数的作用域
作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变
例一:
name='alex'
def foo():
name='lhf'
def bar():
print(name)
return bar
func=foo()
func()
例二:
def foo():
name = 'xieys'
def bar():
name = 'weiwj'
def tt():
print(name)
return tt
return bar
bar = foo()
tt = bar()
tt()
foo()()() #这里的效果跟前面三句效果一样
匿名函数
匿名函数就是不需要显式的指定函数,格式:
lambda 形参 : 返回值
a = lambda x: x + '_sb'
print(a('alex'))
b = lambda x,y:x**y # lambda 后面紧跟的是函数的形参 : 后面跟的是return返回的值
print(b(2,3))
f = lambda x,y: x if x > y else y #lambda表达式也可以也判断,如果条件 x > y 就返回x,否则就返回y
print(f(6,5))
一般匿名函数是和其他函数搭配使用
#例1:用max算字典key对应值最大的是多少 l=[3,2,100,999,213,1111,31121,333] print(max(l)) dic={'k1':10,'k2':100,'k3':30} print(max(dic)) print(dic[max(dic,key=lambda k:dic[k])]) 结果: 31121 k3 100 #例2: 用map计算列表元素的幂次方 res = map(lambda x:x**2,[1,5,7,4,8]) for i in res: print(i) 输出 1 25 49 16 64
高阶函数
满足俩个特性任意一个即为高阶函数
1.函数的传入参数是一个函数名
2.函数的返回值是一个函数名
array=[1,3,4,71,2] ret=[] for i in array: ret.append(i**2) print(ret) #如果我们有一万个列表,那么你只能把上面的逻辑定义成函数 def map_test(array): ret=[] for i in array: ret.append(i**2) return ret print(map_test(array)) #如果我们的需求变了,不是把列表中每个元素都平方,还有加1,减一,那么可以这样 def map_test(array,func=lambda x: x**2): ''' :param array: :param func: 处理函数,这里写了一个默认的匿名函数,返回一个数的平方 :return: ''' result = [] for i in array: result.append(func(i)) return result a = [1,4,2,56,21,3,10] print(map_test(a,lambda x:x+1)) print(map_test(a,lambda x:'偶数' if x % 2 else '奇数' )) msg = 'sadnwqoiqwd' print(map_test(msg,lambda x:x.upper())) print(list(map(lambda x:x.upper(),msg))) #系统自带的map对象,作用跟map_test的作用一样,在python3中返回的是一个迭代器,所以说要list转换,在python2中返回的是一个list 输出的结果: [2, 5, 3, 57, 22, 4, 11] ['偶数', '奇数', '奇数', '奇数', '偶数', '偶数', '奇数'] ['S', 'A', 'D', 'N', 'W', 'Q', 'O', 'I', 'Q', 'W', 'D'] ['S', 'A', 'D', 'N', 'W', 'Q', 'O', 'I', 'Q', 'W', 'D']
movie_people = ['sb_alex','sb_booble','sb_json','xieys','sb_qaz'] def filter_test(people_ls): ''' 过滤包含某个特性的值 :param people_ls: :return: ''' ret = [] for i in people_ls: if not(i.startswith('sb')): ret.append(i) return ret print(filter_test(movie_people)) movie_people = ['sb_alex','sb_booble','sb_json','xieys','sb_qaz'] movie_people1 = ['alex_sb','booble_sb','sb_json','xieys','sb_qaz'] def filter_test(func,array): ret = [] for i in array: if not func(i): ret.append(i) return ret print(filter_test(lambda x:x.startswith('sb'),movie_people)) print(filter_test(lambda x:x.endswith('sb'),movie_people1)) print(list(filter(lambda x:not x.endswith('sb'),movie_people1))) #系统自带的filter功能,跟自己写的相反,如果不加not 这里取的就是结尾是sb的有哪些,
num_l = [1,3,4,100] def reduce_test(array): res = 0 for num in array: res += num return res print(reduce_test(num_l)) def reduce_test1(func,array,init=None): if init == None: res = array.pop(0) else: res = init for num in array: res = func(res,num) return res print(reduce_test1(lambda x,y:x+y,num_l,10)) print(reduce_test1(lambda x,y:x+y,num_l)) print(reduce_test1(lambda x,y:x*y,num_l)) from functools import reduce num_l = [1,3,4,100] print(reduce(lambda x,y:x+y,num_l)) #系统自带的reduce函数 print(reduce(lambda x,y:x*y,num_l))
#当然了,map,filter,reduce,可以处理所有数据类型 name_dic=[ {'name':'alex','age':1000}, {'name':'wupeiqi','age':10000}, {'name':'yuanhao','age':9000}, {'name':'linhaifeng','age':18}, ] #利用filter过滤掉千年王八,万年龟,还有一个九千岁 def func(x): age_list=[1000,10000,9000] return x['age'] not in age_list res=filter(func,name_dic) for i in res: print(i) res=filter(lambda x:x['age'] == 18,name_dic) for i in res: print(i) #reduce用来计算1到100的和 from functools import reduce print(reduce(lambda x,y:x+y,range(100),100)) print(reduce(lambda x,y:x+y,range(1,101))) #用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sb name=['alex','wupeiqi','yuanhao'] res=map(lambda x:x+'_sb',name) for i in res: print(i)
内置函数

abs(-1) -- > 结果为1 divmod(10,3) -- >结果是(3,1) 把10除以3 得到的记过给一个元组,元组的第一个元素为商,第二个元素为余数 all([1,2,3,'']) -- > False,列表中所有的为True,返回值才为True any([1,2,3,'']) -- > True,列表中只要有一个值为True,返回值就为True bin(3) --- > 将3转换为二进制,结果为0b11 bool() --> 布尔值转换 bytes(‘你好’,encoding('utf-8')) -- > 把字符串按照指定的格式转换为字节码 dict() -- > 转换为字典 dif(object) --> 查看对象里的方法 enumerate(iter) --->用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。 eval(str) 1、把字符串中的数据结构给提取出来 2、将字符串中的表达式进行运算 filter() -- > 过滤某元素 float() --> 转换为浮点类型 format() --> 字符串格式化 frozenset() --> 不可变集合 globals --> 全局变量 #可hash的数据类型即不可变数据类型,不可hash的数据类型即可变数据类型 hash(str) -->传入 值计算出hash值返回 help(object) --> 查看对象的帮助文档 hex(x) --> 将十进制转换为16进制 oct(x) --> 将十进制转换为8进制 id(object) -- > 打印对象的内存地址 input() -- > 等待用户输入 int() --> 转换为整型 isinstance(1,int) --> 判断1是不是int的实例,判断对象是那个类的实例 len() --> 对象的长度 list() --> 转换为列表 globals() --> 打印当前级别的所有全局变量 locals() --> 打印当前级别的所有局部变量 max(iter) ---> 取最大值,注意不同类型间不能比较,默认从第一个元素比较,第一个元素如果取出最大的,就不会比较后面的元素,如果第一个元素没有分出大小,继续往后比较,还是和之前一样,如果比较出大小就不再往后比较 l = [ (5,'e'), (1,'a'), (3,'c') ] print(max(l)) 输出结果为 (5,'e') 也可以和zip结合使用比较字典value值,同时把key也打印出来 k = { 'sda': 12, '23': 123 } print(list(max(zip(k.values(),k.keys())))) 输出结果为 [123,'23'] 更加高级的用法: people = [ {'name' : 'alex','age' : 10000}, {'name' : 'qaz','age' : 9000}, {'name' : 'qwe','age' : 10001}, {'name' : 'asb','age' : 18}, ] print(max(people,key=lambda dic:dic['age'])) 结果: {'name': 'qwe', 'age': 10001} min(iter) ---> 取最小值 zip(x,y) --->函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。 chr() ---> 将asiic码转换为对应的字符 ord() ---> 将字符转换为对应的asiic码 pow(3,3) ---> 相当于3**3 ,如果有第三个参数如pow(3,3,2)相当于3**3%2 print() ---> 输出 range(100) --->可创建一个0-99整数列表,一般用在 for 循环中。 reversed() ---> 反转 set() ---> 转换为集合 slice() ---> 切片 sorted() ---> 排序,跟max,min的原理一样 例1 people = [ {'name' : 'alex','age' : 10000}, {'name' : 'qaz','age' : 9000}, {'name' : 'qwe','age' : 10001}, {'name' : 'asb','age' : 18}, ] print(sorted(people,key=lambda dic:dic['age'])) 结果: [{'name': 'asb', 'age': 18}, {'name': 'qaz', 'age': 9000}, {'name': 'alex', 'age': 10000}, {'name': 'qwe', 'age': 10001}] 例2 name_d = { 'qaz':900, 'qwda':300, 'qwrewt':200 } print(sorted(name_d.items(),key=lambda tup:tup[1])) print(sorted(zip(name_d.values(),name_d.keys()))) 结果: [('qwrewt', 200), ('qwda', 300), ('qaz', 900)] [(200, 'qwrewt'), (300, 'qwda'), (900, 'qaz')] str() ---> 转换成字符串 sum() ---> 求和 tuple() ---> 转换为元组 type() --- > 查看数据类型 __import__() ---> 当导入文件为字符串时,用import不能直接导入,如要用__import__(字符串文件名)才能导入 import 调用sys操作系统,然后操作系统再调用__import__
字典的运算:最小值,最大值,排序 salaries={ 'egon':3000, 'alex':100000000, 'wupeiqi':10000, 'yuanhao':2000 } 迭代字典,取得是key,因而比较的是key的最大和最小值 >>> max(salaries) 'yuanhao' >>> min(salaries) 'alex' 可以取values,来比较 >>> max(salaries.values()) >>> min(salaries.values()) 但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键 >>> max(salaries,key=lambda k:salary[k]) 'alex' >>> min(salaries,key=lambda k:salary[k]) 'yuanhao' 也可以通过zip的方式实现 salaries_and_names=zip(salaries.values(),salaries.keys()) 先比较值,值相同则比较键 >>> max(salaries_and_names) (100000000, 'alex') salaries_and_names是迭代器,因而只能访问一次 >>> min(salaries_and_names) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: min() arg is an empty sequence sorted(iterable,key=None,reverse=False)
浙公网安备 33010602011771号