目录
函数是封装好的,可以重复使用,能提高应用的模块性和代码的重复利用率。Python提供了许多内建函数,比如print()。但也可以自己创建函数,这被叫做用户自定义函数。
定义一个函数
规则:
- 函数代码块以def关键词开头,后接函数标识符名称和圆括号()。
- 传入参数和自变量必须放在圆括号内,圆括号里还可以定义参数。
- 函数体里可以存放函数说明。
- 函数内容以冒号开始,自带缩进。
- return[表达式]结束函数,返回一个值给调用方。不带表达式的return相当于返回none。
- ruturn 多个结果,如:return x,y,z..
语法
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配的。
实例
#def定义一个函数
def MyFirstFunction():
print('迈出第一步')
print('成功在等着你')
print('不放弃')
#调用函数
MyFirstFunction()
运行结果:
迈出第一步
成功在等着你
不放弃
写一个带参数的函数:
def add(num1,num2):
return(num1+num2)
print(add(5,6))
运行结果:
11
函数参数
形参(parameter)和实参 (argument):上述中的num1和num2叫作形参(只占据一个位置),5,和4叫作实参(具体的参数值)
以下是调用函数时使用的参数类型:
- 必须参数
- 关键字参数
- 默认参数
- 不定长参数(收集参数、可变参数)
必须参数
必需参数必须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
调用printme()函数,你必须传入一个参数,不然会出现语法错误:
#可写函数说明
def printme( str ):
"打印传入的字符串"
print (str)
return
#调用printme函数
printme()
以上实例输出结果:
raceback (most recent call last):
File "test.py", line 10, in <module>
printme()
TypeError: printme() missing 1 required positional argument: 'str'
关键字参数
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
以下实例在调用函数时不再担心参数顺序导致出错:
def SaySome(name,words):
print(name+'->'+words)
SaySome('小白','加油')
SaySome('加油','小白')
SaySome(words='加油',name='小白')
以上实例运行结果:
小白->加油
加油->小白
小白->加油
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值:
def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )
以上实例输出结果:
名字: runoob
年龄: 50
------------------------
名字: runoob
年龄: 35
不定长参数(收集参数、可变参数)
当你不知道需要多少参数时(在参数前加*)就能解决。这些参数叫做不定长参数。
实例:
def test(*params):
print('参数长度是:',len(params));
print('第二个参数是:',params[1]);
test(1,'小鱼',3.14,5,6,7,8)
运行结果:
参数长度是: 7
第二个参数是: 小鱼
注意:如果还存在除不定长参数以外的其他参数,必须在调用函数时将值赋给形参,否则将自动把所有参数给不定长参数。
另外一种情况:
#如果不赋值exp=8,将自动将所有参数给*params
def test(*params,exp):
print('参数长度是:',len(params));
print('第二个参数是:',params[1]);
test(1,'小鱼',3.14,5,6,7,exp=8)
运行结果:
参数长度是: 6
第二个参数是: 小鱼
还有一种就是参数带两个星号 **基本语法如下:
def functionname([formal_args,] **var_args_dict ):
"函数_文档字符串"
function_suite
return [expression]
加了两个星号 ** 的参数会以字典的形式导入。
实例:
def printinfo( arg1, **vardict ):
print ("输出: ")
print (arg1)
print (vardict)
# 调用printinfo 函数
printinfo(1, a=2,b=3)
以上实例输出结果:
输出:
1
{'a': 2, 'b': 3}
声明函数时,参数中星号 * 可以单独出现,例如:
def f(a,b,*,c):
return a+b+c
如果单独出现星号 * 后的参数必须用关键字传入。
>>> def f(a,b,*,c):
... return a+b+c
...
>>> f(1,2,3) # 报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1,2,c=3) # 正常
6
>>>
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。 例如:
def greetPerson(*name):
print('Hello', name)
greetPerson('Runoob', 'Google')
输出结果:
Hello ('Runoob', 'Google')
匿名函数
python 使用 lambda 来创建匿名函数
所谓匿名,即不再使用 def 语句这样标准的形式定义一个函数。
- lambda 只是一个表达式,函数体比 def 简单很多。
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
lambda 函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
如下实例:
>>> g=lambda x:2*x+1
>>> g(5)
11
变量作用域
Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种,分别是:
- L (Local) 局部作用域
- E (Enclosing) 闭包函数外的函数中
- G (Global) 全局作用域
- B (Built-in) 内置作用域(内置函数所在模块的范围)
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
g_count = 0 # 全局作用域
def outer():
o_count = 1 # 闭包函数外的函数中
def inner():
i_count = 2 # 局部作用域
内置作用域是通过一个名为 builtin 的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:
>>> import builtins
>>> dir(builtins)
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:
>>> if True:
... msg = 'I am from Runoob'
...
>>> msg
'I am from Runoob'
>>>
实例中 msg 变量定义在 if 语句块中,但外部还是可以访问的。
如果将 msg 定义在函数中,则它就是局部变量,外部不能访问:
>>> def test():
... msg_inner = 'I am from Runoob'
...
>>> msg_inner
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'msg_inner' is not defined
>>>
从报错的信息上看,说明了 msg_inner 未定义,无法使用,因为它是局部变量,只有在函数内可以使用。
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:
total = 0 # 这是一个全局变量
def sum( arg1, arg2 ):
total = arg1 + arg2 # total在这里是局部变量.
print ("函数内是局部变量 : ", total)
return total
#调用sum函数
sum( 10, 20 )
print ("函数外是全局变量 : ", total)
以上实例输出结果:
函数内是局部变量 : 30
函数外是全局变量 : 0
global 和 nonlocal关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了。
global 关键字修改全局变量 (在全局变量前加global即可以修改)
count=5
def MyFun():
global count
count=10
print(10)
MyFun()
以上实例输出结果:
10
nonlocal关键字修改局部变量与(global相似),强调参数不是局部变量
def Fun1():
x=5
def Fun2():
nonlocal x #强制声明x不是局部变量
x *=x
return x
return Fun2()
Fun1 () #调用Fun1
以上实例输出结果:
25
函数嵌套
如下实例:
注意 :只能在fun1()里面调用fun2()不能在外部调用内部函数
函数的高级话题
filter函数:筛选
filter(None或函数,可迭代序列)
当默认为None时,筛选掉非True。如下:
>>> filter(None,[1,0,False,True])
<filter object at 0x03800470>
>>> list(filter(None,[1,0,False,True]))
[1, True]
下面实例:筛选奇数
>>> list(filter(lambda x:x%2,range(10)))
[1, 3, 5, 7, 9]
map函数(序列中的映射函数)
内置高阶函数,它接收一个函数 f 和一个list,并把函数 f 依次作用在list的每个元素上,得到一个新的list并返回。
map(None或函数,可迭代序列)
如下实例:函数将会为range(10)列表中的每一个元素平方。
>>> list(map(lambda x:x*2,range(10)))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>