函数
函数的定义
注意事项:
函数定义语法:
def 函数名([参数列表]):
'''注释'''
函数体
函数形参不需要声明类型,也不需要指定函数返回值类型
即使该函数不需要接收任何参数,也必须保留一对空的圆括号
括号后面的冒号必不可少
函数体相对于def关键字必须保持一定的空格缩进 Python允许嵌套定义函数
形参与实参
对于绝大多数情况下,在函数内部直接修改形参的值不会影响实参,而是创建一个新变量。例如:
>>> def addOne(a):
print(id(a), ':', a)
a += 1
print(id(a), ':', a)
>>> v = 3
>>> id(v)
1599055008
>>> addOne(v)
1599055008 : 3
1599055040 : 4
>>> v
3
>>> id(v)
1599055008
在有些情况下,可以通过特殊的方式在函数内部修改实参的值。
>>> def modify(v): # 使用下标修改列表元素值
v[0] = v[0]+1
>>> a = [2]
>>> modify(a)
>>> a
[3]
>>> def modify(v, item): # 使用列表的方法为列表增加元素
v.append(item)
>>> a = [2]
>>> modify(a,3)
>>> a
[2, 3]
也就是说,如果传递给函数的实参是可变序列,并且在函数内部使用下标或可变序列自身的原地操作方法增加、删除元素或修改元素时,实参也得到相应的修改。
>>> def modify(d): #修改字典元素值或为字典增加元素
d['age'] = 38
>>> a = {'name':'Dong', 'age':37, 'sex':'Male'}
>>> a
{'age': 37, 'name': 'Dong', 'sex': 'Male'}
>>> modify(a)
>>> a
{'age': 38, 'name': 'Dong', 'sex': 'Male'}
调用带有默认值参数的函数时,可以不对默认值参数进行赋值,也可以为其赋值,具有很大的灵活性。
>>> def say(message, times=1 ):
print(message*times)
>>> say('hello')
hello
>>> say('hello',3)
hello hello hello
>>> say('hi',7)
hi hi hi hi hi hi hi
下面的函数使用指定分隔符将列表中所有字符串元素连接成一个字符串。
>>> def join(lst, sep=None):
return (sep or ' ').join(lst)
>>> aList = ['a', 'b', 'c']
>>> join(aList)
'a b c'
>>> join(aList, ',')
'a,b,c'
注意:默认值参数必须出现在函数参数列表的最右端,任何一个默认值参数右边不能有非默认值参数。
默认值参数只在函数定义时被解释一次 可以使用“函数名.__defaults__”查看所有默认参数的当前值
>>> i = 3
>>> def f(n=i): # 参数n的值仅取决于i的当前值
print(n)
>>> f()
3
>>> i = 5 # 函数定义后修改i的值不影响参数n的默认值
>>> f()
3
>>> f.__defaults__ # 查看函数所有默认值参数的当前值
(3,)
通过关键参数,实参顺序可以和形参顺序不一致,但不影响传递结果,避免了用户需要牢记位置参数顺序的麻烦。
>>> def demo(a,b,c=5):
print(a,b,c)
>>> demo(3,7)
3 7 5
>>> demo(a=7,b=3,c=6)
7 3 6
>>> demo(c=8,a=9,b=0)
9 0 8
可变长度参数
可变长度参数主要有两种形式:在参数名前加1个星号*或2个星号**。
*parameter用来接收多个位置实参并将其放在元组中。
**parameter接收多个关键参数并存放到字典中。
*parameter的用法
>>> def demo(*p):
print(p)
>>> demo(1,2,3)
(1, 2, 3)
>>> demo(1,2)
(1, 2)
>>> demo(1,2,3,4,5,6,7)
(1, 2, 3, 4, 5, 6, 7)
**parameter的用法
>>> def demo(**p):
for item in p.items():
print(item)
>>> demo(x=1,y=2,z=3)
('x', 1)
('y', 2)
('z', 3)
参数传递的序列解包
传递参数时,可以通过在实参序列前加一个星号将其解包,然后传递给多个单变量形参。
>>> def demo(a, b, c):
print(a+b+c)
>>> seq = [1, 2, 3]
>>> demo(*seq)
6
>>> tup = (1, 2, 3)
>>> demo(*tup)
6
>>> dic = {1:'a', 2:'b', 3:'c'}
>>> demo(*dic)
6
>>> Set = {1, 2, 3}
>>> demo(*Set)
6
>>> demo(*dic.values())
abc
如果函数实参是字典,可以在前面加两个星号进行解包,等价于关键参数。
>>> def demo(a, b, c):
print(a+b+c)
>>> dic = {'a':1, 'b':2, 'c':3}
>>> demo(**dic)
6
>>> demo(a=1, b=2, c=3)
6
>>> demo(*dic.values())
6
return语句
return语句用来从一个函数中返回一个值,同时结束函数。
对于以下情况,Python将认为该函数以return None结束,返回空值:
函数没有return语句;
函数有return语句但是没有执行到;
函数有return也执行到了,但是没有返回任何值。
变量作用域
变量起作用的代码范围称为变量的作用域,不同作用域内变量名可以相同,互不影响。
在函数内部定义的普通变量只在函数内部起作用,称为局部变量。当函数执行结束后,局部变量自动删除,不再可以使用。
局部变量的引用比全局变量速度快。
全局变量会增加函数之间的隐式耦合。
全局变量可以通过关键字global来定义。这分为两种情况:
一个变量已在函数外定义,如果在函数内需要为这个变量赋值,并要将这个赋值结果反映到函数外,可以在函数内使用global将其声明为全局变量。
如果一个变量在函数外没有定义,在函数内部也可以直接将一个变量定义为全局变量,该函数执行后,将增加一个新的全局变量。
注意:
在某个作用域内任意位置只要有为变量赋值的操作,该变量在这个作用域内就是局部变量,除非使用global进行了声明。
如果局部变量与全局变量具有相同的名字,那么该局部变量会在自己的作用域内隐藏同名的全局变量。
lambda表达式
lambda表达式可以用来声明匿名函数(也可以定义具名函数),也就是没有函数名字的临时使用的小函数,尤其适合需要一个函数作为另一个函数参数的场合。
>>> L = [(lambda x: x**2), #匿名函数
(lambda x: x**3),
(lambda x: x**4)]
>>> print(L[0](2),L[1](2),L[2](2)) #调用lambda表达式
4 8 16
>>> D = {'f1':(lambda:2+3), 'f2':(lambda:2*3), 'f3':(lambda:2**3)}
>>> print(D['f1'](), D['f2'](), D['f3']())
5 6 8
>>> L = [1,2,3,4,5]
>>> print(list(map(lambda x: x+10, L))) #lambda表达式作为函数参数
[11, 12, 13, 14, 15]
>>> L
[1, 2, 3, 4, 5]
>>> import random
>>> x = [[random.randint(1,10) for j in range(5)] for i in range(5)]
#包含5个子列表的列表
#每个子列表中包含5个1到10之间的随机数
>>> for item in x:
print(item)
[5, 6, 8, 7, 4]
[1, 5, 3, 9, 4]
[9, 6, 10, 7, 6]
[8, 2, 7, 1, 6]
[1, 7, 5, 3, 5]
python sorted()函数的key参数_葬爱家族小阿杰的博客-CSDN博客_python中sorted函数的key是什么
>>> from random import sample #sample()函数选择多个不重复的随机元素
>>> data = [sample(range(100), 10) for i in range(5)]
>>> for row in data:
print(row)
[72, 47, 87, 27, 75, 14, 0, 67, 16, 52]
[28, 93, 74, 15, 52, 77, 87, 50, 79, 43]
[32, 31, 25, 67, 63, 84, 27, 53, 79, 93]
[22, 3, 56, 91, 75, 83, 51, 89, 14, 45]
[90, 46, 29, 56, 72, 38, 88, 69, 50, 11]
>>> for row in sorted(data):
print(row)
[22, 3, 56, 91, 75, 83, 51, 89, 14, 45]
[28, 93, 74, 15, 52, 77, 87, 50, 79, 43]
[32, 31, 25, 67, 63, 84, 27, 53, 79, 93]
[72, 47, 87, 27, 75, 14, 0, 67, 16, 52]
[90, 46, 29, 56, 72, 38, 88, 69, 50, 11]
>>> from functools import reduce
>>> reduce(lambda x,y:x*y, data[0]) #第一行所有数字相乘
0
>>> reduce(lambda x,y:x*y, data[1]) #第二行所有数字相乘
171018396981432000
>>> list(map(lambda row:row[0], data)) #获取每行第一个元素
[72, 28, 32, 22, 90]
>>> list(map(lambda row:row[data.index(row)], data))
#获取对角线上的元素
[72, 93, 25, 91, 72]
>>> max(data, key=lambda row:row[-1]) #最后一个元素最大的行
[32, 31, 25, 67, 63, 84, 27, 53, 79, 93]
高级话题------map
python中的map函数_菜鸟更要努力呀的博客-CSDN博客_python中的map
内置函数map()可以将一个函数作用到一个或多个序列或迭代器对象上,返回可迭代的map对象。
>>> list(map(str,range(5)))
['0', '1', '2', '3', '4']
>>> def add5(v):
return v+5
>>> list(map(add5,range(10)))
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> def add(x, y):return x+y
>>> list(map(add, range(5), range(5)))
[0, 2, 4, 6, 8]
高级话题------reduce
标准库functools中的reduce()函数可以将一个接受2个参数的函数以迭代的方式从左到右依次作用到一个序列或迭代器对象的所有元素上。
>>> from functools import reduce
>>> seq=[1,2,3,4,5,6,7,8,9]
>>> reduce(lambda x,y:x+y, seq)
45
>>> def add(x, y):
return x + y
>>> reduce(add,range(10))
45
>>> reduce(add,map(str,range(10)))
'0123456789'
高级话题——filter()
内置函数filter将一个函数作用到一个序列上,返回该序列中使得该函数返回值为True的那些元素组成的filter对象。
>>> seq=['foo','x41','?!','***']
>>> def func(x):
return x.isalnum()
>>> list(filter(func,seq))
['foo', 'x41']
>>> seq
['foo', 'x41', '?!', '***']
>>> [x for x in seq if x.isalnum()]
['foo', 'x41']
>>> list(filter(lambda x:x.isalnum(),seq))
['foo', 'x41']
高级话题------生成器函数
包含yield语句的函数可以用来创建生成器对象,这样的函数也称生成器函数。
每次执行到yield语句会返回一个值然后暂停或挂起后面代码的执行,下次通过生成器对象的__next__()方法、内置函数next()、for循环遍历生成器对象元素或其他方式显式“索要”数据时恢复执行。
生成器对象具有惰性求值的特点,适合大数据处理。