Python——函数

函数

为什么需要函数?

如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数。

函数的优势:

从理论上说,不用函数,也能够编程,我们在前面已经写了程序,就没有写函数,当然,用python的内建函数姑且不算了。现在之所以使用函数,主要是:

  1. 降低编程的难度(分而治之的思想)
  2.  代码重用。避免了重复劳动,提供了工作效率。

1.函数创建和调用

1)定义函数的格式:

def 函数名(参数1,参数2,...,参数n):    

       函数体(语句块)

  • 函数名的命名规则要符合python中的命名要求。一般用小写字母和单下划线、数字等组合 匈牙利命名法(sUserName),  驼峰式大小写(userName), 帕斯卡命名法(UserName)
  • def是定义函数的关键词,这个简写来自英文单词define
  • 函数名后面是圆括号,括号里面,可以有参数列表,也可以没有参数
  • 千万不要忘记了括号后面的冒号 函数体(语句块),相对于def缩进,按照python习惯,缩进四个空格

2)函数范例

下面是函数的定义与调用

定义了一个函数之后就可以用help()来查看函数的文档

3)空函数

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

pass 可以用来作为占位符,还没想好怎么写函数的代码,就可以先放一个 pass,让代码能运行起来,这样也就不会报错。

4)函数返回值

所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果.。

没有返回值,默认返回None。


2.变量作用域

1)局部变量

  • 局部变量,就是在函数内部定义的变量  
  • 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响  
  • 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用

例如:

输出结果为:

2)全局变量

如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量。

  • 在函数外边定义的变量叫做全局变量  
  • 全局变量能够在所有的函数中进行访问  
  • 如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错  
  • 如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的  
  • 小技巧: 就近原则

例如:

输出结果为:

在这里要注意global的本质:

global的本质是声明可以修改全局变量的指向, 即变量可以指向新的数据。

  • 不可变类型的全局变量: 指向的数据不能修改, 不使用global时无法修改全局变量。
  • 可变类型的全局变量: 指向的数据可以修改, 不使用global时可以修改全局变量。

例如:

输出结果为:


3.参数传递

1)形参与实参

形参:定义时小括号中的参数,用来接收参数用的,称为 “形参”。

实参:调用时小括号中的参数,用来传递给函数用的,称为 “实参”。

例如:

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

  • 如果参数类型不对,Python 解释器就无法帮我们检查。    
  • 数据类型检查可以用内置函数 isinstance 实现,isinstance查看/判别数据类型的。

例如:

print(isinstance('hello', str))
print(isinstance('hello', int))


输出结果为:
True
False

2)默认参数

我们利用默认参数可以降低调用函数的难度。

默认参数注意事项:

  • 有多个参数时,变化大放前面,变化小的放后面;
  • 必选参数在前,默认参数在后
     

例如:

def mypow(x: int, y: int = 2) -> int:
    """
    求x的y次方
    """
    return x ** y

# 如果传递一个参数, x=3, y没有传递就是默认值2;
print(mypow(3))
# 如果传递2个参数, x=3, y有默认值2, 但是3会覆盖默认值,也就是求2的三次方;
print(mypow(2, 3))

输出结果为:

3)可变参数

可变参数就是传入的参数个数是可变的,可以是 1 个、2 个到任意个,还可以是 0 个。

如果已经有一个 list 或者 tuple,要调用一个可变参数怎么办?

  • Python 允许你在 list 或 tuple 前面加一个 * 号;  
  • 把 list 或 tuple 的元素变成可变参数传进去

例如:

 *nums用来接收多个变量/参数, 接收近来的nums是一个元组;
def numSquare(*nums):
    """
    求n个数的平方和
    """
    # print(nums)
    result = 0
    for num in nums:
        result += pow(num, 2)
    print(result)
numSquare()
numSquare(1)
numSquare(1, 2, 3)
numSquare(3, 4, 5, 6, 7)

# # *score可以存多个数值;
# low, *score, high = [1, 2, 3, 4, 5, 6100]

输出结果为:

4)关键字参数

  • 关键字参数允许传入 0 个或任意个含参数名的参数; 
  • 这些关键字参数在函数内部自动组装为一个 dict;  
  • 关键字参数用**kwargs

例如:

# **kwargs: 关键字参数, 接收的kwargs是一个字典;
def recordStudentInfo(name, sid, **kwargs):
    """
    录入学生信息, 必填的内容姓名和学号, 其他的可以自己输入
    """
    print("""
    
    姓名: %s
    学号: %s
    
    """%(name, sid))

    for key, value in kwargs.items():
        print("\t %s: \t%s" %(key, value))

recordStudentInfo("kevin", '001', score=100, courses=['python', 'c', 'Linux'])

输出结果为:


4.匿名函数

匿名函数指一类无须定义标识符的函数或子程序。

Python用 lambda 语法定义匿名函数,只需用表达式而无需申明。(省略了用def声明函数的标准步骤)

1)lambda 标准形式

lambda函数的语法只包含一个语句,如下:

       lambda 形参:返回值

 lambda 后面先跟参数,它能接收任何数量的参数,冒号后面跟返回值,注意只能返回一个表达式的值。

 

在这里举一个简单的例子来看一下匿名函数的实现,比如求两个数的和,用 def 来定义函数的步骤如下:

def sum(arg1:int, arg2:int)->int:
    """
    求两个数的和
    """
    return  arg1 + arg2

print("运行结果: ", sum(1, 2))
print("运行结果: ", sum(3, 5))

但是用 lambda 函数的时候就无需定义一个函数了,用简单的一步就可以实现两数之和,步骤如下:

lambda_sum = lambda arg1, arg2 :  arg1+arg2
print("运行结果: ", lambda_sum(1, 2))
print("运行结果: ", lambda_sum(3, 5))

2)lambda 函数应用场合

①应用场合1: 函数作为参数传递

def定义函数的参数也是可以用函数去传递的,这样我们就可以用lambda去改变函数参数,从而实现我们的功能。

例如下面这一段程序:

def myFun(num1, num2, fun=pow):
    print('num1=', num1, end=', ')
    print('num2=', num2, end=', ')
    print("result=", fun(num1, num2))

myFun(2, 3)
myFun(2, 3, lambda x, y: x + y)
myFun(2, 3, lambda x, y: x * y)
myFun(2, 3, lambda x, y: x ** y)

输出结果为:

定义的函数参数默认为 pow 函数,是求一个数的几次方的函数。第一个输出结果就是默认的2的3次方,第二个用lambda使函数功能发生变化,成了求两数之和了;第三个则是求两数的乘积了。

②应用场合2: 作为内置函数的参数

lambda函数还可以用在内置函数中,使原本很长的代码可以简化好多,并且也不会很难理解。

比如lambda用在内置的排序函数中:

输出结果为:

在这里说明一下排序的两种方法:

第一种:列表中有针对列表的 .sort 排序方法,比如上面的案例中就用到了列表的 .sort 的方法,它在默认情况下从小到大(升序)的方式对列表排列的。另外可以对它输入reverse,输入的reverse是一个bool值,reverse=True时则对列表进行从大到小(降序)排列。

第二种:sorted()函数排序法,括号中输入要排序的列表,就会对其进行从小到大重排列。

为了对lambda函数有更深刻的了解,下面就举一个lambda和排序的综合小练习:

问题描述: 有一个整数列表(10个元素), 要求调整元素顺序,把所有的奇数放在前面,偶数放在后面。

代码如下:

li = [30, 10, 21, 32, 45, 56, 23, 23, 23, 56]
print(sorted(li, key=lambda x: 1 if x % 2 == 0 else 0))

输出为:

代码中用到了三元运算表达式,使代码更加简洁明了。


5.递归函数

一个函数在内部会调用它自己本身,这个函数就是所谓的递归函数。为了形象的说明递归函数,接下来举几个比较经典的例子。

1)求数的阶乘

首先来看一下阶乘的规律:

代码如下:

def recursive_factorial(num):
    """
    使用递归求num的阶乘
    """
    # 如果num等于0或者1, 返回1;
    if num in (0, 1):
        return 1
    # num的阶乘为num*(num-1)!
    else:
        return num * recursive_factorial(num - 1)


print("3的阶乘: ", recursive_factorial(3))
print("6的阶乘: ", recursive_factorial(6))

结果为:

2)斐波那契数列

斐波那契数列(Fibonacci sequence),又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)。

代码如下:

def fib(num):
    """
    斐波那契数列
    """
    if num <= 2:
        return 1
    else:
        return fib(num - 1) + fib(num - 2)
result = fib(6)
print(result)

结果如下:

3)汉诺塔问题

印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

思路如下:

代码如下:

moveCount = 0
def hanoi(n, a='A', b='B', c='C'):
    """
    :param n:盘子个数
    :param a:初始塔
    :param b:缓存塔
    :param c:目标塔
    :return:移动次数
    """
    if n == 1:
        global moveCount
        moveCount += 1
        print(a, "--->", c)
    else:
        # 只是调用自己, 并没有真实的移动;
        # 1). 打开冰箱门
        hanoi(n - 1, a, c, b)   
        # 2). 把大象放进去
        hanoi(1, a, b, c)
        # 3). 把冰箱门close
        hanoi(n - 1, b, a, c)
hanoi(3)
print("移动次数:", moveCount)

结果为:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值