14.函数基础
一、什么是函数
函数基本概念
1、函数是对程序逻辑进行结构化或过程化的一种编程方法
2、将整块代码巧妙地隔离成易于管理的小块
3、把重复代码放到函数中而不是进行大量的拷贝,这样既能节省空间,也有助于保持一致性
4、通常函数都是用于实现某一种功能
函数格式
python定义函数使用def关键字,一般格式如下
def 函数名(参数列表):
函数体
函数名的命名规则:
函数名必须以下划线或字母开头,可以包含任意字母、数字或下划线的组合。不能使用任何的标点符号;
函数名是区分大小写的。
函数名不能是保留字
函数 vs 过程
1、两者都是可以被调用的实体
2、传统意义上的的函数,可能不带任何输入参数,经过一定的处理,最后向调用者传回返回值
3、其中一些函数则是布尔类型,返回一个零值或非零值
4、过程是简单、特殊、没有返回值的函数
5、Python的过程就是函数,因为解释器会隐式地返回默认值None
返回值与函数类型
1、函数会向调用者返回一个值,而实际编程中大部分偏函数更接近过程,不显示地返回任何东西
2、把过程看待成函数的语言通常对于"什么都不返回"的函数设定了特殊的类型或者值的名字 ,这些函数在Python中对应的返回对象类型是none
3、当没有显式地返回元素或如果返回None时,Python会返回一个None
下面的hello()函数就像一个过程,没有返回值。如果保存了返回值,则该值为None
>>> def hello():
print "hello world"
>>> hello()
hello world
>>> res = hello()
hello world
>>> res
>>> print res
None
>>> type(res)
<type 'NoneType'>
>>>
返回的对象的数目 | Python实际返回的对象 |
0 | None |
1 | object |
>1 | tuple |
上表总结了从一个函数中返回的对象的数目,以及Python实际返回的对象
4种函数的类型
函数根据有没有参数,有没有返回值,可以相互组合,一共有4种
1、无参数,无返回值
2、无参数,有返回值
3、有参数,无返回值
4、有参数,有返回值
注意:
写函数,不要在函数中写print()
函数是以功能为导向的,除非测试的时候,才可以写print()
无参数,无返回值的函数
1、此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数
def printMenu():
print('--------------------------')
print(' xx涮涮锅 点菜系统')
print('')
print(' 1. 羊肉涮涮锅')
print(' 2. 牛肉涮涮锅')
print(' 3. 猪肉涮涮锅')
print('--------------------------')
printMenu()
执行结果:
--------------------------
xx涮涮锅 点菜系统
1. 羊肉涮涮锅
2. 牛肉涮涮锅
3. 猪肉涮涮锅
--------------------------
无参数,有返回值的函数
1、此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数
#!/usr/bin/env python #coding:utf8 def getTemperature(): # 这里是获取温度的一些处理过程 # 为了简单起见,先模拟返回一个数据 return 24 temperature = getTemperature() print('当前的温度为:%d' % temperature)
执行结果:
当前的温度为:24
2、一个函数到底有没有返回值,就看有没有return,因为只有return才可以返回数据
3、函数中,可以有多个return语句,但是只要执行到一个return语句,那么就意味着这个函数的调用完成
有参数,无返回值的函数
def 函数名(形参列表):
语句
此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数
在调用函数时,如果需要把一些数据一起传递过去,被调用函数就需要用参数来接收
参数列表中变量的个数根据实际传递的数据的多少来确定
有参数,有返回值的函数
此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数
# 计算1~num的累积和
def calculateNum(num):
result = 0
i = 1
while i<=num:
result = result + i
i+=1
return result
result = calculateNum(100)
print('1~100的累积和为:%d'%result)
执行结果:
1~100的累积和为:5050
分析:
1.定义函数calculateNum(num),把参数100加入到传递到num中
2.把0赋值给result,1赋值给i然后进行判断;假若i的值小于等于参数100则执行while循环,否则执行return result
3.执行完函数里面的语句后执行result = calculateNum(100),即把返回值赋值给result,最终打印result
二、调用函数
1、调用的方式为函数名([实参列表])
2、如果调用的函数 在定义时有形参,那么在调用的时候就应该传递参数
3、调用时,实参的个数和先后顺序应该和定义函数中要求的一致
4、如果调用的函数有返回值,那么就可以用一个变量来进行保存这个值
函数操作符
1、同大多数语言相同,python用一对圆括号调用函数
2、如果没有加圆括号,只是对函数的引用
3、任何输入的参数都必须放置在括号中
4、作为函数声明的一部分,括号也会用来定义那些参数
#!/usr/bin/env python #coding:utf8 def foo(): print 'hello' foo() print foo
执行结果:
hello <function foo at 0x000000000351FDD8>
函数的执行顺序
例子1:
def fun():
print 'test1'
def fun():
print 'test2'
fun()
执行结果:
test2
下面的fun将上面的fun覆盖掉了;因此若是定义函数名时,若有同名的函数,则靠近调用语句的函数生效
例子2:
#!/usr/bin/env python
#coding:utf-8
def x(fun):
def y():
print 'test1'
return y
def f():
print 'test2'
x(f)
x(f),注意:x(f)中的f没有加括号(),即f为参数。将f作为参数传入x(),x()中的y()函数返回的是y即函数名所以没有执行y函数。所以最终打印出为无结果。
例子3:
#!/usr/bin/env python
#coding:utf-8
def x(fun):
def y():
print 'test1'
return y
def f():
print 'test2'
x(f())
执行结果:
test2
x(f()),注意:x(f())中f后面是有括号的,即f作为函数传给x。将f()函数传给x()函数,先执行f()函数打印出test2,再执行x()函数,因为x()中的y()函数返回的是y即函数名所以没有执行y函数。所以最终打印结果为test2。
例子4:
#!/usr/bin/env python
#coding:utf-8
def x(fun):
def y():
print 'test1'
return y()
def f():
print 'test2'
x(f)
执行结果
test1
x(f),注意:x函数中的y函数返回的值是y函数,即return y()。x(f)中f作为参数传给x函数,所以f()函数就不执行了,执行x函数,因为return y(),所以执行y函数打印出test1。最终打印结果为test1。
例子5:
def x(fun):
def y():
print 'test1'
return y()
def f():
print 'test2'
x(f())
执行结果:
test2
test1
x(f()),注意:x(f())中f后面是有括号的,即f作为函数传给x;x函数中的y函数返回的值是y函数,即return y()。将f()函数传给x()函数,先执行f()函数打印出test2,再执行x函数,因为return y(),所以执行y函数打印出test1。最终执行打印结果为test2 test1。
例子6:
#!/usr/bin/env python
#coding:utf-8
def x(fun):
def y():
print 'test1'
print fun()
return y()
def f():
return 'test2'
x(f)
执行结果:
test1
test2
x(f),注意:x(f)中f后面没有括号,即f作为参数传入x()函数。将f作为参数带入x函数执行,因为return y()所以执行y函数打印出ttest1;再执行print fun()语句,此时相当于func()=f(),即开始执行f()函数打印出test2。所以最终打印结果为test1 test2
三、创建函数
def语句
1、函数是用def语句来创建的,语法如下:
def function_name(arguments):
"function_documentation_string"
function_body_suite
2、标题行由def关键字,函数的名字,以及参数的集合(如果有的话)组成
3、def子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字串,和必需的函数体
3、函数外部的代码要想获取函数的执行结果,就可以在函数里面用return语句,把结果返回
4、通常函数体内有多条return语句;一旦第一个return语句得到执行,整个函数将立即终止;
5、如果return 后面带一个print 或者return ,则后面的不执行
6、如果未在函数中指定return,那么这个函数的返回值就是None
7、return 语句是Python语言中函数返回的一个值,每个函数都应该有一个返回值;其中,return返回值可以是一个数值,一个字符串,一个布尔值或者一个列表。
8、return语句可以出现在函数体中的任何位置
9、在函数定义中,形式参数和return语句都是可选的
10、return表示函数调用的结束,并将结果返回至函数调用处
函数中一定要有return 返回值才是完整的函数,如果你没有定义Python 函数返回值,那么得到一个结果是None对象,而None表示没有任何值
下面举个例子:
通过这两个简单的对比,大家是不是能看出来return的重要性了吧。其实return没有什么特别的用法,只需要记住函数要有返回值即可。
前向引用
1、函数不允许在函数未声明之前对其进行引用或者调用
在函数bar()没有声明之前:
def foo():
print 'in foo'
bar()
foo() #报错,因为bar没有定义,名字错误是当访问没有初始化的标识符时才产生的异常
定义完bar()函数之后
def foo():
print 'in foo'
bar()
def bar():
print 'in bar'
foo() #正常执行,虽然bar的定义在foo定义后面
因为即使 在 foo()中对 bar()进行的调用出现在 bar()的定义之前,但 foo()本身不是在 bar()声明之前被调用的。换句话说,我们声明 foo(),然后再声明 bar(),接着调用 foo(),但是到那时,bar()已经存在了,所以调用成功
执行结果:
in foo
in bar
函数属性
1、你可以获得每个python模块、类和函数中任意的名称空间
2、你可以在模块 foo 和 bar 里都有名为 x 的一个变量,,但是在将这两个模块导入你的程序后,仍然可以使用这两个变量。所以,
即使在两个模块中使用了相同的变量名字,这也是安全的,因为句点属性标识对于两个模块意味了不同的命名空间
3、函数属性是python另外一个使用了句点属性标识并拥有名字空间的领域
def foo():
'foo() -- properly created doc string'
def bar():
pass
bar.__doc__ = 'Oops, forgot the doc str above'
bar.version = 0.1
执行结果:
>>> help(foo)
Help on function foo in module __main__:
foo()
foo() -- properly created doc string
>>> print bar.version
0.1
>>> print foo.__doc__
foo() -- properly created doc string
>>> print bar.__doc__
Oops, forgot the doc str above
内部/内嵌函数
1、在函数体内创建另外一个函数是完全合法的,这种函数叫做内部/内嵌函数
2、有时也叫嵌套函数
3、最明显的创造内部函数的方法是在外部函数的定义体内定义函数(用 def 关键字)
4、内部函数一个有趣的方面在于整个函数体都在外部函数的作用域之内。
5、一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用
例子1:
#!/usr/bin/env python
#coding:utf-8
def foo():
def bar():
print "bar() is called"
print 'foo() is called '
bar()
foo()
执行结果:
foo() is called
bar() is called
例子2:
#!/usr/bin/env python
#coding:utf-8
def foo():
def bar():
print "bar() is called"
print 'foo() is called '
bar()
print foo() #因为当没有显式地返回元素或如果返回None时,Python会返回一个None
执行结果:
foo() is called
bar() is called
None
例子3:
>>> def foo():
... def bar():
... print 'bar() is called'
... print 'foo() is called'
... bar()
>>> foo()
foo() is called
bar() is called
>>> bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined
如果没有任何对 bar()的外部引用,那么除了在函数体内,任何地方都不能对其进行调用,这就是在上述代码执行到最后你看到异常的原因
例子4:
#!/usr/bin/env python #coding:utf8 def testB(): print '---- testB start----' print '这里是testB函数执行的代码...(省略)...' print '---- testB end----' def testA(): print '---- testA start----' testB() print '---- testA end----' testA()
执行结果:
---- testA start----
---- testB start----
这里是testB函数执行的代码...(省略)...
---- testB end----
---- testA end----
如果函数A中,调用了另外一个函数B,那么先把函数B中的任务都执行完毕之后才会回到上次 函数A执行的位置
函数的返回值
1、多数情况下,函数并不直接输出数据,而是向调用者返回值
2、函数的返回值使用return关键字
3、没有return的话,函数默认返回None
>>> def foo():
... res = 3 + 4
>>> i = foo()
>>> print i
None
总结:
return的作用。
1.在函数中,遇到return结束函数。
2.将值返回给函数的调用者。
四、函数参数
定义参数
1、形式参数:函数定义时,紧跟在函数名后(圆括号内)的参数被称为形式参数,简称形参。由于它不是实际存在变量,所以又称虚拟变量;
在定义函数和函数体的时候使用形参,目的就是在函数调用的时候接收实参(实参个数,类型应与实参一一对应)
2、实际参数:在主调函数中调用一个函数时,函数名后面括弧中的参数称为“实际参数”,简称实参;
调用函数时候传给函数的变量,可以是常量,变量,表达式,函数,传给形参
3、形参是虚拟的,不占用内存空间,形参变量只有在调用时才分配内存单元,实参是一个变量,占用空间,数据传送单向,只能实参传给形参,不能形参传给实参。
传递参数
1、调用函数时,实参的个数需要与形参个数一致
2、实参将依次传递给形参
>>> def foo(x, y):
... print 'x=%d, y=%d' % (x, y)
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 2 arguments (0 given)
>>> foo(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 2 arguments (1 given)
>>> foo(3, 4)
x=3, y=4
位置参数
1、与shell脚本类似,程序名以及参数都以位置参数的方式传递给python程序
2、使用sys模块的argv列表接收
3、位置参数必须以在被调用函数中定义的准确顺序来传递
4、另外,没有任何默认参数(见下一个部分)的话,传入函数(调用)的参数的精确的数目必须和声明的数字一致。
[root@py01 bin]# vim args.py
#!/usr/bin/env python
import sys
print sys.argv
[root@py01 bin]# ./args.py hello world
['./args.py', 'hello', 'world']
默认参数
1、默认参数就是声明了默认值的参数
2、因为给参数赋予了默认值,所以在函数调用时,不向该参数传入值也是允许的
3、python 中用默认值声明变量的语法是所有的位置参数必须出现在任何一个默认参数之前
def func(posargs, defarg1=dval1, defarg2=dval2,...):
"function_documentation_string"
function_body_suite
例子:
>>> def pstar(num = 30):
... print '*' * num
...
>>> pstar()
******************************
>>> pstar(40)
****************************************
关键字参数
1、关键字参数的概念仅仅针对函数的调用
2、这种理念是让调用者通过函数调用中的参数名字来区分参数
3、这种规范允许参数或者不按顺序,因为解释器能通过给出的关键字来匹配参数的值
4、当参数允许"缺失“的时候,也可以使用关键字参数.这取决于函数的默认参数
#!/usr/bin/env python #coding:utf8 def getInfo(name, age): print "%s's age is %s" % (name, age) getInfo('bob',23) getInfo(age = 23, name = 'bob')
执行结果:
bob's age is 23
bob's age is 23
参数组
1、Python 同样允许程序员执行一个没有显式定义参数的函数,
2、相应的方法是通过一个把元组(非关键字参数)或字典(关键字参数)作为参数组传递给函数
3、存在这样的特性允许你把变量放在元组和/或者字典里,并在没有显式地对参数进行逐个声明的情况下,调用函数
4、可变长的参数组必须在位置参数和默认参数之后
5、语法:
func(*tuple_grp_nonkw_args, **dict_grp_kw_args)
6、其中的 tuple_grp_nonkw_args 是以元组形式体现的非关键字参数组, dict_grp_kw_args 是装有关键字参数的字典
7、实际上,你也可以给出形参!这些参数包括标准的位置参数和关键字参数,所以在 python 中允许的函数调用的完整语法为 :
func(positional_args, keyword_args,*tuple_grp_nonkw_args, **dict_grp_kw_args)
该语法中的所有的参数都是可选的---从参数传递到函数的过程来看,在单独的函数调用时,每个参数都是独立的
例子1:# 注意传递的参数对应
#!/usr/bin/env python #coding:utf8 def fun(a, b, *args, **kwargs): """可变参数演示示例""" print "a =", a print "b =", b print "args =", args print "kwargs: " for key, value in kwargs.items(): print key, "=", value fun(1, 2, 3, 4, 5, m=6, n=7, p=8) # 注意传递的参数对应
执行结果:
a = 1 b = 2 args = (3, 4, 5) kwargs: p = 8 m = 6 n = 7
例子2:# 注意元组与字典的传参方式
#!/usr/bin/env python #coding:utf8 def fun(a, b, *args, **kwargs): """可变参数演示示例""" print "a =", a print "b =", b print "args =", args print "kwargs: " for key, value in kwargs.items(): print key, "=", value c = (3, 4, 5) d = {"m":6, "n":7, "p":8} fun(1, 2, *c, **d) # 注意元组与字典的传参方式
执行结果:
a = 1 b = 2 args = (3, 4, 5) kwargs: p = 8 m = 6 n = 7
例子3:
#!/usr/bin/env python #coding:utf8 def fun(a, b, *args, **kwargs): """可变参数演示示例""" print "a =", a print "b =", b print "args =", args print "kwargs: " for key, value in kwargs.items(): print key, "=", value c = (3, 4, 5) d = {"m":6, "n":7, "p":8} fun(1, 2, c, d) # 注意不加星号与上面的区别
执行结果:
a = 1 b = 2 args = ((3, 4, 5), {'p': 8, 'm': 6, 'n': 7}) kwargs:
例子4: 多个单个变量,整合成元组
def func(*args):
print args
# 执行方式一
func(11,33,4,4454,5)
#输出结果:(11,33,4,4454,5)
# 执行方式二
li = [11,2,2,3,3,4,54]
func(li)
#输出结果:([11,2,2,3,3,4,54])
#如果想输入的列表,不想让列表称谓元组里的仅一个元素而是让列表的元素成为元组的元素加*即可
func(*li)
#输出结果:(11,2,2,3,3,4,54)
#############################################################
1、接受多个参数
2、内部自动构造元组
3、序列,*,避免内部构造元组
执行结果:
(11, 33, 4, 4454, 5)
([11, 2, 2, 3, 3, 4, 54],)
(11, 2, 2, 3, 3, 4, 54)
例子5:整合为字典变量
#!/usr/bin/env python #coding:utf8 def func(**kwargs): print kwargs # 执行方式一 func(name='tom',age=18) # 执行方式二 li = {'name':'tom', 'age':18, 'gender':'male'} func(**li)
执行结果:
{'age': 18, 'name': 'tom'}
{'gender': 'male', 'age': 18, 'name': 'tom'}
例子6:整合了*args,**args
#!/usr/bin/env python
#coding:utf-8
def func(*args, **drgs):
print args
print drgs
func(11,22,33,44,k1='tom',k2='jack')
执行结果:
(11, 22, 33, 44)
{'k2': 'jack', 'k1': 'tom'}