============================================================================
==== 注该文档源于个人在学习廖雪峰老师的Python教程时候的随笔,参考网址:
==== https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/
==== 其中有少量引用原句,并未标明,若侵权,将致歉删除。
==== 本文属于学习笔记,如果理解不正确之处,还望海涵,多请指教
=============================================================================
接Python学习tips(1)
8. 函数
8.1 函数调用
函数名本质上是对函数的对象的引用,完全可看做是一个变量,可以赋值给另外一个变量,也既是给函数起一个别名。
8.2 定义函数
定义函数要使用def语句,依次写出函数名,括号,括号中的参数和冒号(:),然后函数体要使用缩进。函数返回值使用return语句。
如果将函数my_func()函数定义保存为funcs.py文件中,那么可以在该文件的当前目录下启动Python解释器,用
from funcs import my_func
导入my_func()函数。注意funcs是文件名,不包含.py扩展名。
8.3空函数
如:
define temp_fun():
pass
使用pass语句作为占位符。注意:pass语句可以用于其他地方作为占位符,让程序先跑起来。
8.4 函数参数检查
使用Python内置方法:isinstance(),如:
def my_abs(x):
if not isinstance(x,(int,float)):
ralse TypeError('bad operand type')
if x > 0:
return x
else
return -x
8.5 返回多个参数
如:
import math
def move(x,y,step,angle = 0):
nx = x + step*math.cos(angle)
ny = y + step*math.sin(angle)
return nx,ny
注:import math 语句表示导入math包,则可以引用math中的cos() sin()等函数
其实,这是一种假象,返回的是tuple元组,但是为了方便使用,省略了括号。
8.6 参数
8.6.1 位置参数
python中普通参数称为位置参数
如:
def power(x):
return x*x
对于上述函数中的参数x就是位置参数
8.6.2 默认参数
在定义函数的时候,给参数初始化一个默认值,这个参数就称为默认参数
如:
def power(x,n = 2)
s= 1
while n > 0:
n = n-1
s = s * x
return s
对于上述函数中n为默认参数,在调用时候,如果仅有一个参数,则n就使用默认的参数进行运算
Python的函数也允许传入默认参数。
设置默认参数注意事项:
a.必选参数在前,默认参数在后
b.另外,变化频次高的变量放在前面,变化频次小的变量放在后面。
c.当有多个默认参数的时候,只改变后一个默认参数的时候,调用函数时候需要将参数名带上
如:
def eroll(name,gender,age = 6,city = 'SH')
print(name)
…
调用:
enroll('ww','M',city = 'SQ')
d.重点:默认参数必须指向不变对象,如str,tuple,但不推荐list。
注:如果非要使用list等可变对象作为默认参数,请切记,加入判断使用默认参数的时候,对默认参数复位。
8.6.3 可变参数
所谓可变参数,是指函数的参数可以是多个不同的值,即传入参数的个数是可变的
当使用普通参数实现这样的功能的时候,需要首先将多个参数装载成list或者tuple,具体实现表现为传入参数时候多个参数需要使用()或者[]包裹。
而可变参数的方法不需要将参数使用()或者[]包裹,直接传入多个参数,个数不定。实现方法和普通参数发的函数定义区别仅仅在与多加上一个星号(*).
普通方法:
define sumup(numbers):
sum = 0
for x in numbers:
sum = sum + x
return sum
调用方法:
>>>sumup([1,2,3,4])
可变参数法:
define sumup(*numbers):
sum = 0
for x in numbers:
sum = sum + x
return sum
调用方法:
>>>sumup(1,2,3,4)
在实现可变参数的函数后,对于已经存在的list或tuple参数可以采用如下方法调用:
>>>nums = [1,2,3,4]
>>>sumup(*nums)
即使用星号*把list或者tuple中的参数变成可变参数传入函数中。
8.6.4关键字参数
可变参数函数允许传入0或者任意个参数,这些可变参数在函数调用的时候被自动组装成一个tuple.而关键字参数同样允许参数0或者任意个含参数名的参数,这些参数在函数内部自动组装成一个dict.
如:
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数;也可以传入除了必选参数外的参数,
>>> person('Michael', 30)
name: Michael age: 30 other: {}
>>> person('Bob', 35,city='Beijing')
name: Bob age: 35 other: {'city':'Beijing'}
>>> person('Adam', 45, gender='M',job='Engineer')
name: Adam age: 45 other: {'gender': 'M','job': 'Engineer'}
关键字参数的作用:扩展函数功能。
如下,一种简化调用关键字参数的方法。
>>> extra = {'city': 'Beijing','job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city':'Beijing', 'job': 'Engineer'}
8.6.5命名关键字参数
如:
def person(name, age, **kw):
if 'city' in kw:
# 有city参数,使用if...in...语句来判断,命名关键字参数是否包含某项
pass
if 'job' in kw:
# 有job参数
pass
print('name:', name, 'age:', age, 'other:', kw)
如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
def person(name, age, *, city, job):
print(name, age, city, job)
和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
调用方法,仅限传入如上命名的两种关键字。
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
命名参数必须赋值。
命名参数可以有缺省值。
命名参数在使用的时候,要将key值标明,否则,会被当做可变参数(当然是,如果函数定义中带有可变参数;如果定义中没有带有可变参数,应该会报错吧?)
8.6.6 参数组合:
在Python中共有必选参数(位置参数?),默认参数,可变参数,关键字参数和命名关键字参数,共5种参数类型,这5中参数类型又可以组合使用。但,请注意,使用的时候参数顺序必须按照上述顺序来排列。
所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。
对上述表述解释:任何参数的组合都可以看做是可变参数和关键字参数的组合。可以将必须参数/默认参数装载成tuple,其余参数都是关键字参数,装载成dict,打包放在可变参数中。
*args是可变参数,args接收的是一个tuple;输出参数时候可以看到用圆括号()包裹
**kw是关键字参数,kw接收的是一个dict。输出参数看到用大括号{}包裹
以及调用函数时如何传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3));
关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})。
使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。
8.7 递归函数
8.7.1定义:如果一个函数内部调用自身,则称为递归函数。
如,求取阶乘的函数:
def fact(n):
if n = 1:
return 1
return n*fact(n-1)
递归函数较之于循环函数逻辑更为清晰。但是递归函数的有着一下特点需要注意:
* 防止栈溢出,因为递归函数每调用一次自身就需要将前一次调用压入栈中,直到最终可计算才逐层退栈。如果递归深度较深,需要注意防止栈溢出
8.7.2尾递归
解决调用栈溢出的方法是通过尾递归优化。
定义:函数返回调用函数本身并且不能包含表达式。
如,将上述阶乘函数改为尾递归:
def fact(n):
return fact_iter(n,1)
def fact_iter(num,product):
if num==1:
return product
return fact_iter(num-1,num*product)
可以看出,fact_iter函数返回函数本身,在函数调用前就会将下一步的参数进行计算,传入。
尾递归实际上将递归的多次调用+多层调用栈转化成仅有多次调用来解决,在每次调用之前,计算出下次调用的参数,只占用一个栈帧。
尾递归的方式,在上述实例中可以理解为从尾部开始逆向运算,每次调用首先计算值再递归调用下一次。而递归方法,返回的是一个表达式,将运算压入栈中,直到满足条件的时候再运算,且是正向运算。
|