#2 python函数定义

python中函数的定义使用 def 语句,依次写函数名,括号,参数, 冒号 :,然后缩进语句块,有返回值的使用return语句,如果没有返回值的,可以写'return',或者'return None'

def my_fun(x):
  if x >=0:
    return x
  else:
    return -x

一.空函数

python中使用 pass 语句

def none_fun:
  pass

这样有些代码如果没有想好就可以先跳过,当然 pass 语句还可以用于其它语句中

if x >= 100:
  pass

二.函数参数

1.默认参数

python的默认参数和C#中的默认参数很类似,一般将变化小的参数写在后面,可以提供有名实参而不用考虑参数的顺序等

def enroll(name, gender, age=6, city='wuhan'):
  print('name:', name)
  print('gender:', gender)
  print('age:', age)
  print('city:', city)

enroll('james', 'F')
enroll('kobe', 'M', city='Los Angle')

值得注意的是:默认参数必须指向不变对象

如果指向的是可变对象,比如list类型,则可能出现意想不到的结果

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

>>> add_end()
['END']

>>> add_end()
['END', 'END']

这是因为python函数在定义时,默认参数L的值被计算出来了,即[],因为L也是一个变量,指向对象[],每次调用该函数,如果改变L的内容,下次调用时,默认参数的内容就改变了

可以改为:

# 将默认参数指向一个不可变对象None
def add_end(L=None):
  if L is None:
    L = []
  L.append('END')  
  return L

>>> add_end()
['END']

>>> add_end()
['END']

使用 is 关键词,这关键词和js中一致

2.可变参数*

其实就是js中的spread操作符,python中使用 * 表示, 可变参数在函数调用时实际上自动组装成一个元组tuple

def calc(*numbers):
  sum = 0
  for n in numbers:
    sum += n * n
  return sum

# 对于一般的数,可以直接传入
calc(1, 2)    
calc(1, 2, 3)

# 对于list tuple等集合元素,可以像js中先展开
# list [1, 2, 3]
L = [1, 2, 3]
calc(*L)

T = (1, 2, 3)
calc(*T)

3.关键字参数 **

关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装成一个 dict, 表示方式为 **

示例:

def person(name, age, **kw):
  print('name:', name, 'age:', age, 'other:', kw)

# 关键字参数自动组装成字典dict
>>> person('james', 28, city='wuhan', hobby='base')
name: james, age: 28, other: {city: 'wuhan', hobby='base'}

# 可以直接传入一个字典dict, 但是需要在字典前保留 '**'
>>> info = {gender: 'M', hobby: 'basketball'}
>>> person('james', 28, **info)
name: james, age: 28, other: {gender: 'M', hobby: 'basketball'}

值得注意的是,传入到函数中的info字典只是外部定义的info的拷贝,函数中的info改变不会影响到外部的info字典

4.命名关键字参数

用于限制关键字参数的名字,比如说,下面的'city', 'job', 如果2个关键字参数少一个都会报错,同时也可以提供默认值,使用方式有几种

1.在命名关键字参数前添加一个*作为特殊参数分割符

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

>>> person('Louis', 28, city='Beijing')
> TypeError: person() missing 1 required keyword-only argument: 'job'

2.如果使用了可变参数,则可变参数后面的参数为命名关键字参数

# 可变参数*args后面的 city, job为命名关键字参数
def person(name, age, *args, city, job)
  print(name, age, args, city, job)

>>> person('james', 19, 'beijng', city='wuhan', job='worker')
james 19 ('beijng',) wuhan worker

# 缺少命名关键字参数则会报错
>>>  person('james', 19, 'beijng')
TypeError: person() missing 2 required keyword-only arguments: 'city' and 'job'

参数组合

python中定义函数,可以使用必选参数,默认参数,可变参数,关键字参数,命名关键字参数,但是要注意这5种参数的顺序是:可变参数,默认参数,可变参数,命名关键字参数, 关键字参数

示例:

# a,b必选参数, c默认参数,*args可变参数, **kw 关键字参数
def f1(a, b, c=0, *args, **kw):
  print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

# a,b必选参数, c默认参数,d命名关键字参数, **kw 关键字参数
def f2(a, b, c=0, *, d, **kw):
  print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

# 使用fun(*args, **kw)的形式
>>> 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)的形式去调用它

三.引入模块

这一点和js中的import很像,假如当前路径下有个文件名叫 'hello.py', 这个文件里面有个函数叫 'my_abs',可以在其它模块中引用这个函数

from hello import my_abs

引入语言自带的一些库函数可以直接使用improt

import math

另外在terminal中可以使用下列命令查看文件的内容

more hello.py

四.返回多个值

这个其实是语法糖,本质上返回的是 tuple 数据类型,省略括号之后就看起来像返回多个值

import math

def move(x, y, step, angle=0):
  nx = x + step * math.cos(angle)
  ny = y + step * math.sin(angle)
  return nx, ny

>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print(x, y)
151.96152422706632, 70.0

# 可以写为
>>> t = move(100, 100, 60, math.pi / 6)
>>> print(t)
(151.96152422706632, 70.0)
# 可以看出返回的实际上是一个tuple

五.递归函数

递归函数就是函数自调用,使用尾部调用的方式可以优化递归调用,这点和其它语言一样。

尾部调用就是函数返回的时候,调用自身本身,并且return语句不能包含表达式

# 没有进行尾部调用优化
def fact(n):
  if n == 1:
    return 1
  return n * fact(n - 1)  # return后面有表达式

# 尾部调用优化

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)  

六.参数检查 raise

可以使用 raise 语句返回错误类型,相当于js中的throw,抛出错误

def my_abs:
  if not isinstance(x, (int, float)):
    raise TypeError('bad operand type')
  if x >= 0:
    return x
  else:
    return -x

另外可以看到:

  • isinstance: 这个用于判断数据类型,和js中的instanceOf类似

总结

本章主要介绍python中的函数,函数的定义形式,函数参数的几种类型,以及其它的一些知识:

  • 使用 def 来定义函数
  • pass 语句, raise 语句(相当于js中的throw,抛出错误), is 关键词, isinstance() 方法(用于检查对象类型)
  • 函数参数类型:必选参数,默认参数,任意参数,命名关键字参数, 关键字参数
  • import 引入模块,from xxx import some_fun 引入某个文件中的某个函数模块

总的来说,python中的函数参数定义和其它语言差别不是很大,最主要的不同在于命名关键字参数,关键字参数

2017年3月4日 17:31:46

你可能感兴趣的:(#2 python函数定义)