廖雪峰Python教程阅读笔记——2. Python函数

2. 函数

常用的函数:abs()求绝对值、max()可以接收多个参数,求其中最大值。可以用help(max)来查看所有的max函数信息。

数据类型转换:Python内置的常用函数还包括数据类型转换函数,比如int()函数可以把其他数据类型转换为整型。int()str()bool()

函数名其实就是指向一个函数对象的引用。完全可以用其他变量名代替函数名,相当于给函数起了个别名

2.1定义函数

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


def my_abs(x):

   if(x>0)

      return x;

   else 

      return -x;

注意:在函数内部,执行到return语句时,函数执行完毕,并返回。如果没有return语句,函数也能正常返回,但是返回值为Nonereturn None可以简写为return.

在Python**交互环境中定义函数时,注意Python会出现...提示,函数定义结束后,连按两次回车键,会重新返回到>>>提示符下。如果把my_abs()函数定义保存到abstest.py文本文件下,那么,可以在该文件目录下**启动Python解释器,用from abstest import my_abs来导入my_abs()函数。注意:abstest是文件名(不包含.py后缀)。

  • 空函数

    如果要定义一个什么也不做的函数,可以在缩进块中使用pass语句。

    
    def nop():
    
     pass;
    

    pass可以用来作为占位符,比如现在没想好函数怎么写。可以先放一个pass

  • 参数检查

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

    但是,如果参数类型不正确,Python解释器就无法帮我们检查。我们可以在函数体中,加入数据类型检查语句isinstance()。比如对my_abs()函数参数限制只能接收整数和浮点数:

    
    def my_abs(x):
    
       if not isinstance(x,(int,float))
    
       if(x>0)
    
          return x;
    
       else 
    
          return -x;
    

    isinstance()函数定义:

    
    >>> help(isinstance)
    
    Help on built-in function isinstance in module builtins:
    
    
    
    isinstance(obj, class_or_tuple, /)
    
        Return whether an object is an instance of a class or of a subclass   thereof.
    
    A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to
    
    check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B)
    
    or ...`` etc.
    
    >>>
    
  • 返回多个值

    比如,在游戏中经常需要从一个点移动到另外一个点,给出坐标、位移和角度,就可以计算出新的坐标:

    
    import math
    
    def move(x,y,step,angle=0):
    
       mx = x + step*math.cos(angle)
    
       my = y + step * math.sin(angle)
    
       return mx,my
    

    import math就是引入math包,并允许后续使用math包里的sincos等函数。然后我们可以使用

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

    注:看似返回的两个值,其实是一个tuple类型的对象

  • 小结:

    1. 定义函数时,要确定函数名和参数个数,参数类型不用确定。

    2. 如果有必要,可以先对参数类型进行检查。

    3. 函数体内可以使用return随时返回函数结果。

    4. 函数执行完毕,也没用return时,自动return None

    5. 函数可以同时返回多个值,但其实就是一个tuple

2.2 函数的参数

Python函数的定义除了常规的参数外,还可以使用默认参数可变参数关键字参数

2.2.1 位置参数

例如:计算x^n。

 def power(x,n):
    s = 1
    while n>0:
       n = n - 1
       s = s * n
    return s;

对于这个函数power(x,n)x和n都是位置参数,调用此函数时,传入的两个值按照位置顺序依次赋值给参数x和n。

2.2.2 默认参数

当我们定义了power(x,b)后,原来的power(x)函数则无法使用,调用power(5)时,会报错。此时,可以使用默认参数:

 def power(x,n=2):
    s = 1
    while n>0:
       n = n - 1
       s = s * n
    return s;

此时,调用power(5)power(5,2)都不会出现错误。

设置默认参数时,要注意:

  1. 必选参数在前,默认参数在后,否则Python解释器会报错;

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

  3. 有多个默认参数时,调用的时候,既可以按顺序提供默认参数,也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。

  4. 默认参数必须指向不变对象。

2.2.3 可变参数

在Python函数中,还可以定义可变参数。可变参数就是指传入的参数个数是可变的。可以是0个、1个或多个。

首先,我们想到的是用list和tuple作为参数,携带多个参数。有了可变参数,只需要在参数前面加上*即可。定义可变参数:


def calc(*numbers):

   sum = 0

   for n in numbers:

      sum = sum + n * n

   return sum

可变参数允许传入0个或任意个参数,这些可变参数在函数调用时自动组装成一个tuple

2.2.4 关键字参数

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装成一个dict。比如:


def person(name,age,**kw):

    print('name:',name,'age:',age,'other:',kw)


当调用此函数时,可以传入任意个关键字参数kw指向一个dict对象。


>>>person('Bob',35,city='Beijing')

name: Bob age: 35 other: {'city': 'Beijing'}

可见,传入的关键字参数在函数体内,转换为了dict类型。


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

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

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

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

2.2.5命名关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。

还是以person()函数为例


def person(name,age,**kw):

    if 'city' in kw:

       #如果有city参数

       pass

    if 'job' in kw:

       #如果有job参数

       pass

    print('name:',name,'age:',age,'other:',kw)


但是调用者仍然可以传不受限制的关键字参数:


>>>person('Jack',24,city='Beijing',addr='Guangzhou',zipcode='123456')

>>>

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


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

    print('name',name,'age:',age,'city:',city,'job:',job)

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。

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

2.2.6 参数组合

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

2.2.7小结

  1. 默认参数一定要用不可变对象,如果可变的对象,程序运行时会有逻辑错误。

  2. 要注意定义可变参数和关键字参数的语法:

    *agrs是可变参数,args接收的是一个tuple

    **kw是关键字参数,kw接收一个dict

    可变参数既可以直接传入:func(1,2,3),又可以先组装成listtuple,再通过*args传入:func(*(1,2,3))

    关键字参数既可以直接传入:func(a=1,b=2)有可以先组装dict,再通过**kw传入:func(**{'a':1,'b':2})

  3. 关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。

2.3递归函数

举例,计算n的阶乘


def fact(n):

    if n==1:

       return 1

    return n*fact(n-1)

上面这个递归函数,当n取较大值时,会出现栈溢出异常。递归就是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会增加一层栈帧,每当函数返回依次,就会减少一层栈帧。

解决递归调用栈溢出的方法就是使用尾递归,事实上尾递归和循环的效果是一样的,所以,把循环看成一种特殊的尾递归函数。

尾递归是指,在函数返回的时候,调用自身本身,并且,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)

可以看到,return fact_iter(num-1,num*product)仅返回递归函数本身,num-1num*product在函数调用前就已被计算出来。尾递归调用时,如果做了优化栈不会增长,因此,无论多少次调用也不会导致栈溢出。遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没用做优化。所以上述都是‘废话’

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值