Python学习笔记(七)函数
函数
- 可以实现信息模块化的目标。
- 函数或方法能重复使用,便于日后的调试和维护。
- 从面向对象的角度来看,函数提供了操作接口的方法,有数据隐藏的作用。
根据程序设计的需求,Python的函数大致分为3种:
- 系统内置函数(Built-In Function,BIF),如获取类型的type()函数。
- 提供的函数标准库(Standard Library)。就像导入math模块时,会使用类math提供的类方法。
- 程序设计者使用def关键字自定义的函数。
Python内置函数
太多了,百度找
函数基础
- 定义函数:先以def关键字定义total()函数上及函数主体,它提供的是函数执行的根据。
- 调用程序:从程序语句中“调用函数”total()。
语法如下:
def 函数名称:
函数主体_suite
[return]
- def是关键字,用来定义函数,函数程序区块的开头,尾端要有“:”
- 函数名称:遵守标识符名称的命名规范。
- 参数列表:成为形式参数列表(format argument list),用来接受数值,其名称也适用于标识符名称的命名规范,可以有多个参数,也可以省略参数。
- 函数主体必须缩排,可以是单行或多行语句。
- return:返回运算后的值,无数值返回可省略。
定义函数
下面创建一个Fibonacci序列:
def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
# Now call the function we just defined:
fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
函数体的第一行可以是一个可选的字符串文本;此字符串是该函数的文档字符串,或称为docstring。
如果你使用过其他语言,你可能会反对说:fib 不是一个函数,而是一个过程(子程序),因为它并不返回任何值。事实上,没有return语句的函数也返回一个值,尽管是一个很无聊的值。此值被称为 None(它是一个内置的名称)。如果 None只是唯一的输出,解释器通常不会打印出来。
返回值
用法与其他语言相同
def total(n1, n2, n3):
result = 0
for item in range(n1, n2 + 1, n3):
result += item
return result
print('cal')
key = input('start')
while key == 'y':
start = int(input('input init'))
finish = int(input('input end'))
step = int(input('input mid'))
print('total:{0:,}'.format(total(start, finish, step)))
key = input('start')
def answer(x, y):
return x + y, x * y, x / y
numA = int(input('first:'))
numB = int(input('second:'))
print('answer:', answer(numA, numB))
first:146
second:63
answer: (209, 9198, 2.3174603174603177)
- 返回单个的值或对象。
- 多个值或对象可储存于元组对象中。
- 未使用return语句时,默认返回None。
参数的基本机制
- 实际参数(Actual Argument):在调用函数时,将接受的数据或对象传递给定义参数,默认为位置参数。
- 形式参数(Formal Parameter):定义函数时,用来接收实际参数所传递的数据,进入函数主体执行语句或运算,默认以位置函数为主。
函数的传递
- 传值(call by value):若为数值数据,则先把数据复制一份在传递,原来的参数内容不会受到影响。
- 传址(pass-by-reference):传递的是参数的内存地址,因而会影响原有的变量内容。
//传递参数的规则
- 不可变(Immutable)对象(如数值,字符串):使用对象引用时会先复制一份在传递。
- 可变(Mutable)对象(如列表):使用对象引用时会直接传递内存地址。
def passFun(name, score):
print('name', id(name))
print('score',id(score))
na = 'Mary'; sc = [75, 68]
passFun(na, sc)
print('na', id(na))
print('sc', id(sc))
name 2142017634632
score 2142016869192
na 2142017634632
sc 2142016869192
默认参数值
默认参数值是指自定义函数时,将形参给与默认值,当某个参数没有传递数据时,自定义函数可以使用其默认值。
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
该函数可以通过几种方式调用:
- 只提供必须的参数:
ask_ok('Do you really want to quit?')
- 提供可选参数中的一个:
ask_ok('OK to overwrite the file?', 2)
- 或者提供所有参数:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
关键字函数
函数还可以用kwarg=value形式的关键字参数调用。对于实例,具有以下功能:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
接受一个必须的参数(voltage)和三个可选参数
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
以下调用将无效:
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument
- 调用函数时,第一个参数以位置为主,第二个参数为关键字参数,能正确返回其运算结果
- 相反的,第一个参数以关键字参数为主,第二个参数以位置为主,会发生错误。
任意参数的列表
定义函数的形式参数和调用函数的实际参数一位置为主,才能按序对应。为了让形参和实参更灵活应用,可前缀*和**来搭配使用。定义函数时,以运算表达式来呈现,‘*’和元组相结合,‘**’则与字典配合收集多余的实参。调用函数时,针对实际参数,*运算符拆分可迭代对象,**运算符以映射对象为拆分对象。
形参的*表达式
def concat(*args, sep="/"):
return sep.join(args)
concat("earth", "mars", "venus")
concat("earth", "mars", "venus", sep=".")
'earth/mars/venus'
'earth.mars.venus'
Python3.x以后的版本,还可以在‘*tuple’对象之后加入关键字参数,所以调用函数时,可直接将参数以关键字参数方式来传递。
def student(name, *score, subject = 4):
if subject >= 1 :
print('name:', name)
print('total:', subject, 'subject, score:', *score)
total = sum(score)
print('total:', total, ', average:', '%.4f'%(total/subject))
###
student('Tomas', 78, 65, 93, 81)
student('Dick', 100, 100, 100, subject = 3)
name: Tomas
total: 4 subject, score: 78 65 93 81
total: 317 ,average: 79.2500
name: Dick
total: 3 subject, score: 100 100 100
total: 300 ,average: 100.0000
**表达式与字典配合
def score(**value):
print('score: ', value)
score(Eng = 90, Math = 80, CHI = 70)
def student(msg, **pern):
print(msg, '按学生名字排序')
for key in sorted(pern):
print('{0:8s}{1}'.format(key, pern[key]))
print('-' * 20)
###
low60 = {k : v for k, v in pern.items()
if v < 60}
count = len(low60)
print('low60', count, '人')
print(low60)
student('2015学年', Mary = 90, Steven = 45,
Eric = 75, John = 55, Ivy = 75,
Tomas = 87, Ford = 41, Helen = 88)
作用域
无论是变量还是函数,对于Python而言都有作用域(Scope)。变量根据其作用域可分为下述三种:
- 全局(Global)作用域:适用于整个文件(*.py)
- 局部(Local)作用域:适用于所声明的函数或流程控制的程序区块,离开此范围就会结束其生命周期。
- 内置(Built-In)作用域:由内置函数(BIF)通过builtins模块来建立所使用的范围,在该模块中使用的变量会自动被所有的模块所拥有,它可以在不同的文件中使用。
通常Python程序设计语言根据其作用域可以创建4种函数:全局函数,局部函数,lambda函数和方法。
局部函数与闭包
在Python程序设计语言中,可以在函数中定义其他函数,后者被称为内部函数,局部函数或内置函数。
def exter(x, y):
def internal(a, b):
return divmod(a, b) #return a//b, a%b
return internal(x, y)
print(exter(35, 4))
lambda函数
可以使用 lambda关键字创建小的匿名函数。此函数会返回两个参数的总和: lambda a, b: a+b.。Lambda函数可用于需要函数对象的任何地方。它们在语法上限于单个表达式。语义上,它们只是用于正常函数定义的语法糖。像嵌套的函数定义,lambda 函数可以从包含它的作用域中引用变量:lambda 参数列表, ... :表达式
- lambda函数只会有一行语句
- 表达式不能有return语句
def calc(x, y):
return x ** y
calc = lambda x, y : x ** y
- 自定义函数时,函数名称为calc,可作为调用lambda()函数的变量名称,所以自定义函数有名称,lambda函数无名称,需要借助设置的变量名称。
- 表达式的值在calc()函数中以return形式返回,而lambda()的运算结果由变量calc存储。所以定义函数时,函数主体有多行语句,可以是语句,也可以是表达式。lambda()函数只能有一行语句。
pern = [('Mary', 1988, 'Shanghai'),
('Davie', 1992, 'Hangzhou'),
('Andy', 1999, 'Wuhan'),
('Monica', 1987, 'Shenzhen'),
('Cindy', 1996, 'Shanghai')]
st = lambda item : item[0]
pern.sort(key = st)
print('按名字排序:')
for name in pern:
print('{:6s}, {}, {:10s}'.format(*name))
pern.sort(key = lambda item:item[2], reverse = True)
print('按出生地降序排序:')
for name in pern:
print('{:6s}, {}, {:10s}'.format(*name))
pern.sort(key = lambda item:item[1])
print('按出生年份升序排序:')
for name in pern:
print('{:6s}, {}, {:10s}'.format(*name))
按名字排序:
Andy , 1999, Wuhan
Cindy , 1996, Shanghai
Davie , 1992, Hangzhou
Mary , 1988, Shanghai
Monica, 1987, Shenzhen
按出生地降序排序:
Andy , 1999, Wuhan
Monica, 1987, Shenzhen
Cindy , 1996, Shanghai
Mary , 1988, Shanghai
Davie , 1992, Hangzhou
按出生年份升序排序:
Monica, 1987, Shenzhen
Mary , 1988, Shanghai
Davie , 1992, Hangzhou
Cindy , 1996, Shanghai
Andy , 1999, Wuhan
- 使用filter()函数
def getNums(x):
return x > 2
lt = range(10)
list(filter(getNums, lt))
递归
一个简单的阶乘递归函数
def rec(x):
if x > 0:
return x * rec(x - 1)
else:
return 1
递归的思想与其他程序语言相同,懂得自然懂。