集团站切换校区

验证码已发送,请查收短信

图标

学习文章

当前位置:首页 > >学习文章 > >

{人工智能}python編程之函数

发布时间: 2018-08-10 14:15:26

5.1     实验介绍

5.1.1   关于本实验

本实验主要介绍了 Python 函数的相关知识点和简单操作。

5.1.2    实验目的

          1.理解 Python函数的含义。

           2.掌握和 Python函数相关的操作。

5.2    实验任务配置

5.2.1    概念知识

函数可以提高应用的模块性和代码的重复利用率。在Python 中,string、tuple和 number 是不可变对象,list、dict是可变对象。对于不可变类型,如整数、字符串、元组,函数调用传递的只是值,没有影响到对象本身。对于可变类型,如列表、字典,函数调用时真的将对象传过去,修改之后外部的对象也会受到影响。

5.2.2    实验内容步骤 

1   常用内置函数

比如 int 函数可以把其他类型的数据转化为整数:

>>> int('123') 

123

>>> int(12.34) 

12

>>> float('12.34')

12.34

>>> str(1.23) 

'1.23'

>>> str(100)

 '100'

>>> bool(1) 

True

>>>bool('')

False

步骤 2   函数名

函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:

>>>a = abs      # 变量 a 指向 abs 函数

>>> a(-1)        # 所以也可以通过 a 调用 abs 函数1

步骤 3   定义函数

在 Python 中,定义一个函数要使用 def 语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。我们以自定义一个求绝对值的 my_abs函数为例:

>>> def my_abs(x):

ifx>=0:return x 

else:return–x

如果想定义一个什么事也不做的空函数,可以用 pass语句, 可以用来作为占位符。修改一下my_abs 的定义,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用内置函数 isinstance()实现:

def my_abs(x):

ifnot isinstance(x, (int, float)): 

raise TypeError('bad operand type')

ifx >= 0:return x 

else:return –x

步骤 4   关键字参数

可变参数允许你传入0 个或任意个参数,这些可变参数在函数调用时自动组装为一个 tuple。而关键字参数允许你传入0 个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个 dict。

defperson(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'}

和可变参数类似,也可以先组装出一个 dict,然后,把该 dict 转换为关键字参数传进去:

>>>extra = {'city': 'Beijing', 'job': 'Engineer'}

>>> person('Jack',24, city=extra['city'], job=extra['job']) 

name: Jack age: 24 other: {'city':'Beijing', 'job': 'Engineer'}

当然,上面复杂的调用可以用简化的写法:

>>>extra = {'city': 'Beijing', 'job': 'Engineer'}

>>>person('Jack', 24, **extra)

name: Jack age: 24 other: {'city':'Beijing', 'job': 'Engineer'}

**extra 表示把 extra 这个 dict 的所有 key-value 用关键字参数传入到函数的**kw 参数,kw 将获得一个 dict,注意 kw 获得的 dict 是 extra 的一份拷贝,对kw 的改动不会影响到函数外的extra。

步骤 5   命名关键字参数

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city 和 job 作为关键字参数。这种方式定义的函数如下:

def person(name, age, *, city,job): 

print(name, age, city, job)

和关键字参数**kw 不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。调用方式如下:

>>> person('Jack', 24, city='Beijing',job='Engineer')

Jack24 Beijing Engineer

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

defperson(name, age, *args, city, job): 

print(name, age, args, city, job)

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错命名关键字参数可以有缺省值,从而简化调用:

def person(name, age, *,city='Beijing', job): 

print(name, age, city, job)

由于命名关键字参数 city 具有默认值,调用时,可不传入city 参数:>>>person('Jack', 24, job='Engineer')

Jack 24 Beijing Engineer

使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python 解释器将无法识别位置参数和命名关键字参数。

步骤 6   参数组合

在 Python 中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这 5 种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

比如定义一个函数,包含上述若干种参数:

deff1(a, b, c=0, *args, **kw):

print('a=', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

deff2(a, b, c=0, *, d, **kw):

print('a =', a, 'b =', b, 'c=', c, 'd =', d, 'kw =', kw)

在函数调用的时候,Python 解释器自动按照参数位置和参数名把对应的参数传进去。

>>>f1(1, 2)

a= 1 b = 2 c = 0 args = () kw = {

>>>f1(1, 2, c=3)

a =1 b = 2 c = 3 args = () kw = {}

>>>f1(1, 2, 3, 'a', 'b')

a= 1 b = 2 c = 3 args = ('a', 'b') kw = {}

>>>f1(1, 2, 3, 'a', 'b', x=99)

a = 1 b = 2 c = 3 args = ('a','b') kw = {'x': 99}

>>>f2(1, 2, d=99, ext=None)

a = 1 b = 2 c = 0 d = 99 kw ={'ext': None}

最神奇的是通过一个 tuple 和 dict,你也可以调用上述函数:

>>>args = (1, 2, 3, 4)

>>>kw = {'d': 99, 'x': '#'}

>>>f1(*args, **kw)

a= 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}

>>> args = (1, 2, 3)

>>>kw = {'d': 88, 'x': '#'}

>>>f2(*args, **kw)

a = 1 b = 2 c = 3 d = 88 kw ={'x': '#'}

所以,对于任意函数,都可以通过类似 func(*args, **kw)的形式调用它,无论它的参数是如何定义的。

步骤 7   递归函数

使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。栈溢出解决方法:

尾递归优化:解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以, 把循环看成是一种特殊的尾递归函数也是可以的。尾递归是指,在函数返回的时候,调用自身本身,并且,return 语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。上面的 fact(n)函数由于returnn * fact(n - 1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:

deffact(n):

  return fact_iter(n, 1)

deffact_iter(num, product):

if num == 1: 

return product

return fact_iter(num - 1, num* product)

可以看到,return fact_iter(num - 1, num* product)仅返回递归函数本身,num - 1 和num* product 在函数调用前就会被计算,不影响函数调用。

上一篇: {人工智能}python之循环语句

下一篇: {人工智能}python編程之字符串

十年老品牌
QQ咨询:450959328 微信咨询:togogozhong 咨询电话:020-38289118 咨询网站客服:在线客服

相关课程推荐

在线咨询 ×

您好,请问有什么可以帮您?我们将竭诚提供最优质服务!