Python(六)语法 函数定义,函数参数

函数

Python内置了很多有用的函数,我们可以直接调用。

要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数abs,只有一个参数。可以直接从Python的官方网站查看文档:

http://docs.python.org/3/library/functions.html#abs

也可以在交互式命令行通过help(abs)查看abs函数的帮助信息。

调用abs函数:

>>> abs(100)
100
>>> abs(-20)
20
>>> abs(12.34)
12.34

调用函数的时候,如果传入的参数数量不对,会报TypeError的错误,并且Python会明确地告诉你:abs()有且仅有1个参数,但给出了两个:

>>> abs(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)

如果传入的参数数量是对的,但参数类型不能被函数所接受,也会报TypeError的错误,并且给出错误信息:str是错误的参数类型:

>>> abs('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

max函数max()可以接收任意多个参数,并返回最大的那个:

>>> max(1, 2)
2
>>> max(2, 3, 1, -5)
3

数据类型转换

Python内置的常用函数还包括数据类型转换函数,比如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

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

>>> a = abs # 变量a指向abs函数
>>> a(-1) # 所以也可以通过a调用abs函数
1

定义函数

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

在Python交互环境中定义函数时,注意Python会出现...的提示。函数定义结束后需要按两次回车重新回到>>>提示符下

>>> def hello(name):
...  return 'hello:'+name
...
>>> hello('xuxu')
hello:xuxu
>>>

函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。

如果没有return语句,函数执行完毕后也会返回结果,只是结果为Nonereturn None可以简写为return

如果你已经把hello()的函数定义保存为fun.py文件了,那么,可以在该文件的当前目录下启动Python解释器,用from fun import hello来导入hello()函数,注意fun是文件名(不含.py扩展名):

>>> from fun import hello
>>> hello('xuxu')
hello:xuxu
>>>

空函数

如果想定义一个什么事也不做的空函数,可以用pass语句:

def nop():
    pass

pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

pass还可以用在其他语句里,比如:

if age >= 18:
    pass

缺少了pass,代码运行就会有语法错误。

调用函数时,如果参数个数不对,Python解释器会自动检查出来,并抛出TypeError:

>>> hello('x','x')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: hello() takes 1 positional argument but 2 were given

但是如果参数类型不对,Python解释器就无法帮我们检查,如下传入数字类型明显和之前定义的参数字符串类型不一致,但是程序没有报错,知道最后返回时,执行到‘hello’+123这一步时才报错:数值类型无法和字符串类型相连

>>> hello(123)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in hello
TypeError: can only concatenate str (not "int") to str

对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用内置函数isinstance()实现

# -*- coding: utf-8 -*-
def hello(name):
 if not isinstance(name,(str)):
  raise TypeError('输入参数不是字符串')
 return('hello:'+name)
>>> hello('1')
'hello:1'
>>> hello(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "E:\python\helloword\fun.py", line 4, in hello
    raise TypeError('输入参数不是字符串')
TypeError: 输入参数不是字符串
>>>

返回多个值

函数可以返回多个值吗?答案是肯定的。

def hello(x,y):
 return x,y
>>> x,y=hello(1,2)
>>> print(x,y)
1 2
>>>

但其实这只是一种假象,Python函数返回的仍然是单一值

>>> r=hello(1,2)
>>> r
(1, 2)

原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。

一道数学题

请定义一个函数quadratic(a, b, c),接收3个参数,返回一元二次方程:

ax2 + bx + c = 0

的两个解。

提示:计算平方根可以调用math.sqrt()函数:

# -*- coding: utf-8 -*-

import math

def quadratic(a,b,c):
 for x in (a,b,c):
  if not isinstance(x,(int,float)):
   raise TypeError('arg type error')
  if a==0:
   return -c/b
  else:
   data=b*b-4*a*c
   if data==0:
    return -b/(2*a)
   elif data<0:
    return '无解'
   elif data>0:
    return (math.sqrt(data)-b)/(2*a),(-math.sqrt(data)-b)/(2*a)
# 测试:
print('quadratic(2, 3, 1) =', quadratic(2, 3, 1))
print('quadratic(1, 3, -4) =', quadratic(1, 3, -4))

if quadratic(2, 3, 1) != (-0.5, -1.0):
    print('测试失败')
elif quadratic(1, 3, -4) != (1.0, -4.0):
    print('测试失败')
else:
    print('测试成功')

函数的参数

Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码

位置参数

我们先写一个计算x2的函数:

>>> def power(x):
...  return x*x
...
>>> power(5)
25

对于power(x)函数,参数x就是一个位置参数。

当我们调用power函数时,必须传入有且仅有的一个参数x

但是如果我们需要计算x的3次方时我们又得写新的函数,以至于我们写x的n次方我们得写无数个函数

此时可以将几次方N当做函数参数

>>> def power(x,n):
...  return x**n
...
>>> power(2,3)
8

但是这样一来如果用户还想像以前一样直接调用power(x)来算平方的时候就会因为缺少必须参数n报错如下:

>>> power(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: power() missing 1 required positional argument: 'n'

默认参数

这个时候,默认参数就排上用场了。由于我们经常计算x2,所以,完全可以把第二个参数n的默认值设定为2:

>>> def power(x,n=2):
...  return x**n
...
>>> power(2)
4
>>> power(2,3)
8

从上面的例子可以看出,默认参数可以简化函数的调用。设置默认参数时,有几点要注意:

一是必选参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面);

>>> def add(x,y=2,z):
...  return x+y+z
...
  File "<stdin>", line 1
SyntaxError: non-default argument follows default argument

因为如果用户调用add(1,3) 那么就会产生歧义,有可能是add(1,2,3),也有可能是add(1,2)

二是如何设置默认参数。

当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数

使用默认参数有什么好处?最大的好处是能降低调用函数的难度。

多个默认参数时既可以按顺序提供默认参数,也可以不按顺序提供默认参数,但要带上参数名

>>> def add(a,b,c=3,d=4):
...  return a+b+c+d
...
>>> add(1,2)
10
>>> add(1,2,4)
11
>>> add(1,2,d=0)
6

add(1,2)相当于参数c和d全部采用默认值

add(1,2,4)相当于参数d采用默认值,也就是1+2+4+4

add(1,2,d=0)相当于指定参数d的值是0,c采用默认值 也就是1+2+3+0

定义默认参数要牢记一点:默认参数必须指向不变对象!举个例子

>>> def add_end(L=[]):
...  L.append('END')
...  return L
...
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

发现如果将L默认参数指向list那么每次执行默认方法时都是在后面累加END 而不是一个END

因为L指向的是一个对象,虽然对象一直没变,但是对象在内存中的值改变了,只需要将L指向不变对象即可

>>> def add_end(L=None):
...  if L==None:
...   L=[]
...  L.append('END')
...  return L
...
>>> add_end()
['END']
>>> add_end()
['END']

可变参数

在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个

在参数前面加了一个*号。在函数内部,参数nums接收到的是一个tuple

>>> def add(*nums):
...  sum=0
...  for num in nums:
...   sum=sum+num
...  return sum
...
>>> add(1,2,3)
6
>>> add()
0
>>>

如果传入的参数时一个list,Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去

>>> list=[1,2,3]
>>> add(*list)
6
>>>

关键字参数

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

>>> def person(name,age,**kw):
...  print('name:',name,'age:',age,'other:',kw)
...
>>> person('xuxu',28,city='wuhan',sex='man')
name: xuxu age: 28 other: {'city': 'wuhan', 'sex': 'man'}

传入dict

>>> dict={'city':'wuhan','sex':'man'}
>>> person('xuxu',28,**dict)
name: xuxu age: 28 other: {'city': 'wuhan', 'sex': 'man'}

命名关键字参数

要限制关键字参数的名字,就可以用命名关键字参数,和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数,命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错

>>> def person(name,*,age):
...  print('name:',name,'age:',age)
...
>>> person('xuxu',age=28)
name: xuxu age: 28
>>> person('xuxu',28)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() takes 1 positional argument but 2 were given

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

>>> def person(name,*args,age):
...  print('name:',name,args,'age:',age)
...
>>> person('xuxu',age=28)
name: xuxu () age: 28
>>> person('xuxu',1,2,3,age=28)
name: xuxu (1, 2, 3) age: 28
>>>

参数组合

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

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

>>> def args(a,b,c=3,*d,e,**kw):
...  print('a:',a,'b:',b,'c:',c,'d:',d,'e:',e,'kw',kw)
...
>>> args(1,2,3,4,4,4,e=5,f=6,g=7)
a: 1 b: 2 c: 3 d: (4, 4, 4) e: 5 kw {'f': 6, 'g': 7}
>>>

猜你喜欢

转载自blog.csdn.net/baiyan3212/article/details/84067301
今日推荐