目录

目标

01. 函数参数和返回值的作用

1.1 无参数,无返回值

1.2 无参数,有返回值

1.3 有参数,无返回值

1.4 有参数,有返回值

02. 函数的返回值 进阶

示例 —— 温度和湿度测量

面试题 —— 交换两个数字

03. 函数的参数 进阶

3.1. 不可变和可变的参数

3.2 缺省参数

3.3 多值参数(知道)

04. 函数的递归

4.1 递归函数的特点

4.2 递归案例 —— 计算数字累加


目标

  • 函数参数和返回值的作用

  • 函数的返回值 进阶

  • 函数的参数 进阶

  • 递归函数

01. 函数参数和返回值的作用

函数根据 有没有参数 以及 有没有返回值,可以 相互组合,一共有 4 种 组合形式

  1. 无参数,无返回值

  2. 无参数,有返回值

  3. 有参数,无返回值

  4. 有参数,有返回值

 

Python学习笔记 之 函数进阶_默认值

定义函数时,是否接收参数,或者是否返回结果,是根据 实际的功能需求 来决定的!

  1. 如果函数 内部处理的数据不确定,就可以将外界的数据以参数传递到函数内部

  2. 如果希望一个函数 执行完成后,向外界汇报执行结果,就可以增加函数的返回值

1.1 无参数,无返回值

此类函数,不接收参数,也没有返回值,应用场景如下:

  1. 只是单纯地做一件事情,例如 显示菜单

  2. 在函数内部 针对全局变量进行操作,例如:新建名片,最终结果 记录在全局变量

注意:

  • 如果全局变量的数据类型是一个 可变类型,在函数内部可以使用 方法 修改全局变量的内容 —— 变量的引用不会改变

  • 在函数内部,使用赋值语句 才会 修改变量的引用

1.2 无参数,有返回值

此类函数,不接收参数,但是有返回值,应用场景如下:

  • 采集数据,例如 温度计,返回结果就是当前的温度,而不需要传递任何的参数

1.3 有参数,无返回值

此类函数,接收参数,没有返回值,应用场景如下:

  • 函数内部的代码保持不变,针对 不同的参数 处理 不同的数据

  • 例如 名片管理系统 针对 找到的名片修改删除 操作

1.4 有参数,有返回值

此类函数,接收参数,同时有返回值,应用场景如下:

  • 函数内部的代码保持不变,针对 不同的参数 处理 不同的数据,并且 返回期望的处理结果

  • 例如 名片管理系统 使用 字典默认值提示信息 提示用户输入内容

    • 如果输入,返回输入内容

    • 如果没有输入,返回字典默认值

02. 函数的返回值 进阶

  • 在程序开发中,有时候,会希望 一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理

  • 返回值 是函数 完成工作后,最后 给调用者的 一个结果

  • 在函数中使用 return 关键字可以返回结果

  • 调用函数一方,可以 使用变量接收 函数的返回结果

问题:一个函数执行后能否返回多个结果?

示例 —— 温度和湿度测量

  • 假设要开发一个函数能够同时返回当前的温度和湿度

  • 先完成返回温度的功能如下:

def measure():
    """返回当前的温度"""
    
    print("开始测量...")
    temp = 39
    print("测量结束...")
    
    return temp

result = measure()
print(result)
  • 在利用 元组 在返回温度的同时,也能够返回 湿度

  • 改造如下:

def measure():
    """返回当前的温度"""

    print("开始测量...")
    temp = 39
    wetness = 10
    print("测量结束...")

    return (temp, wetness)

提示:如果一个函数返回的是元组,括号可以省略


def measure():
	tem = 20
	value = 10

	return tem, value

result = measure()
print(result)

Python学习笔记 之 函数进阶_数据_02

def measure():
    """测量温度和湿度"""

    print("测量开始...")
    temp = 39
    wetness = 50
    print("测量结束...")

    # 元组-可以包含多个数据,因此可以使用元组让函数一次返回多个值
    # 如果函数返回的类型是元组,小括号可以省略
    # return (temp, wetness)
    return temp, wetness

# 元组
result = measure()
print(result)

# 需要单独的处理温度或者湿度 - 不方便
print(result[0])
print(result[1])

# 如果函数返回的类型是元组,同时希望单独的处理元组中的元素
# 可以使用多个变量,一次接收函数的返回结果
# 注意:使用多个变量接收结果时,变量的个数应该和元组中元素的个数保持一致
gl_temp, gl_wetness = measure()

print(gl_temp)
print(gl_wetness)

技巧

  • Python 中,可以 将一个元组 使用 赋值语句 同时赋值给 多个变量

  • 注意:变量的数量需要和元组中的元素数量保持一致

result = temp, wetness = measure()

返回多个值
 

print(abs(0))

print(max(1,4,5,6))


print(int('2322'))
print(int(13.23))
print(int(float('13.98')))
print(float('23.24'))

print(str(121))
print(bool(1))
print(bool(0))
print(bool(-1))
print(bool(''))


# 函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量
# 相当于给这个函数起了一个“别名”
a = abs        # 变量a指向abs函数
print(a(-1))   # 所以也可以通过a调用abs函数


n1 = 255
n2 = 1000
print(hex(n1))
print(hex(n2))


'''
在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
'''
def my_abs(x):
	# 数据类型检查可以用内置函数isinstance()实现
	if not isinstance(x, (int, float)):
		raise TypeError('bad operand type')
	if x >= 0:
		return x
	else:
		return -x

print(my_abs(-9.7))





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)
# 原来返回值是一个tuple
r = move(100,100,60,math.pi/6)
print(r)
print(r[0],r[1])


def quadratic(a,b,c):
	B = (b * b - 4 * a * c)
	if B >= 0:
		ans1 = (-1 * b + math.sqrt(B)) / (2 * a) 
		ans2 = (-1 * b - math.sqrt(B)) / (2 * a) 
	return ans1,ans2

print(quadratic(2,3,1))
print(quadratic(1,3,-4))


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

print(power(5))
print(power(15))
print(power(5,4))


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

print(add_end([1,2,3]))

print(add_end())
print(add_end())
print(add_end())

def addend(L=None):
	if L is None:
		L = []
	L.append('END')
	return L

print(addend())
print(addend())
print(addend())


def calc(numbers):
	sum = 0
	for n in numbers:
		sum = sum + n * n
	return sum
print(calc([1,2,3,4,5]))

def calc2(* numbers):
	sum = 0
	for n in numbers:
		sum = sum + n * n
	return sum
print(calc2(12,32,32,42))
nums = [1,2,3]
print(calc2(nums[0],nums[1],nums[2]))
print(calc2(*nums))



def person(name,age,**kw):
	if 'city' in kw:
		print('has city', '==',end = '')
	if 'job' in kw:
		print('has job', '==',end = '')
	print('name:',name,'age:',age,'other:',kw)

person('Min',30)
person('Bob',35,city='Beijing')
person('Bob',35,city='Beijing',job='Ern')

extra = {'city':'Beijing','job':'Eng'}
person('Jack',24,**extra)


def fact(n):
	if n == 1:
		return 1
	return n * fact(n-1)

print(fact(5))
print(fact(100))
print(fact(100))

# 解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
# 尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。
# 这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
def fec(n):
	return fac_iter(n,1)

def fac_iter(num,product):
	if num==1:
		return product
	return fac_iter(num-1,num*product)

print(fact(6))

def move(n,a,b,c):
	if n==1:
		print(a,'-->', c)
	else:
		move(n-1,a,c,b)		#move the n-1 from a to b
		move(1,a,b,c)       #now,a has just one dish,so just move it to c
		move(n-1,b,a,c)     #now,move the n-1 dishes from b to c

move(4,'A','B','C')

 

Python学习笔记 之 函数进阶_递归_03

 

面试题 —— 交换两个数字

题目要求

  1. 有两个整数变量 a = 6, b = 100

  2. 不使用其他变量,交换两个变量的值

解法 1 —— 使用其他变量

# 解法 1 - 使用临时变量
c = b
b = a
a = c

解法 2 —— 不使用临时变量

# 解法 2 - 不使用临时变量
a = a + b
b = a - b
a = a - b

解法 3 —— Python 专有,利用元组

a, b = b, a
a = 6
b = 100

# 解法1:-使用其他变量
# c = a
# a = b
# b = c

# 解法2:-不使用其他的变量
# a = a + b
# b = a - b
# a = a - b

# 解法3:-Python 专有
# a, b = (b, a)
# 提示:等号右边是一个元组,只是把小括号省略了
a, b = b, a

print(a)
print(b)

Python学习笔记 之 函数进阶_递归_04

Python学习笔记 之 函数进阶_数据_05

 

def demo(num, num_list):

    print("函数内部的代码")

    # 在函数内部,针对参数使用赋值语句,不会修改到外部的实参变量
    num = 100
    num_list = [1, 2, 3]

    print(num)
    print(num_list)
    print("函数执行完成")


gl_num = 99
gl_list = [4, 5, 6]
demo(gl_num, gl_list)
print(gl_num)
print(gl_list)

    

Python学习笔记 之 函数进阶_默认值_06

Python学习笔记 之 函数进阶_默认值_07

 

 

03. 函数的参数 进阶

3.1. 不可变和可变的参数

问题 1:在函数内部,针对参数使用 赋值语句,会不会影响调用函数时传递的 实参变量? —— 不会!

  • 无论传递的参数是 可变 还是 不可变

    • 只要 针对参数 使用 赋值语句,会在 函数内部 修改 局部变量的引用不会影响到 外部变量的引用

问题 2:如果传递的参数是 可变类型,在函数内部,使用 方法 修改了数据的内容,同样会影响到外部的数据

def demo(num_list):

    print("函数内部的代码")

    # 使用方法修改列表的内容
    num_list.append(9)

    print(num_list)

    print("函数执行完成")


gl_list = [1, 2, 3]
demo(gl_list)
print(gl_list)

Python学习笔记 之 函数进阶_数据_08

面试题 —— +=

  • python 中,列表变量调用 += 本质上是在执行列表变量的 extend 方法,不会修改变量的引用

def demo(num, num_list):

    print("函数开始")

    # num = num + num
    num += num

    # 列表变量使用 + 不会做相加再赋值的操作 !
    # num_list = num_list + num_list
    # 本质上是在调用列表的 extend 方法
    num_list += num_list
    # num_list.extend(num_list)

    print(num)
    print(num_list)

    print("函数完成")


gl_num = 9
gl_list = [1, 2, 3]
demo(gl_num, gl_list)
print(gl_num)
print(gl_list)


3.2 缺省参数

  • 定义函数时,可以给 某个参数 指定一个默认值,具有默认值的参数就叫做 缺省参数

  • 调用函数时,如果没有传入 缺省参数 的值,则在函数内部使用定义函数时指定的 参数默认值

  • 函数的缺省参数,将常见的值设置为参数的缺省值,从而 简化函数的调用

  • 例如:对列表排序的方法

gl_list = [6, 3, 9]

# 默认按照升序排序 - 可能会多!
# gl_list.sort()

# 如果需要降序排序,需要执行reverse参数
gl_list.sort(reverse=True)

print(gl_list)
gl_num_list = [6, 3, 9]
​
# 默认就是升序排序,因为这种应用需求更多
gl_num_list.sort()
print(gl_num_list)
​
# 只有当需要降序排序时,才需要传递 `reverse` 参数
gl_num_list.sort(reverse=True)
print(gl_num_list)

指定函数的缺省参数

  • 在参数后使用赋值语句,可以指定参数的缺省值

def print_info(name, gender=True):
​
    gender_text = "男生"
    if not gender:
        gender_text = "女生"
​
    print("%s 是 %s" % (name, gender_text))

提示

  1. 缺省参数,需要使用 最常见的值 作为默认值!

  2. 如果一个参数的值 不能确定,则不应该设置默认值,具体的数值在调用函数时,由外界传递!

缺省参数的注意事项

1) 缺省参数的定义位置

  • 必须保证 带有默认值的缺省参数 在参数列表末尾

  • 所以,以下定义是错误的!

def print_info(name, gender=True, title):

2) 调用带有多个缺省参数的函数

  • 调用函数时,如果有 多个缺省参数需要指定参数名,这样解释器才能够知道参数的对应关系!

def print_info(name, title="", gender=True):
    """
​
    :param title: 职位
    :param name: 班上同学的姓名
    :param gender: True 男生 False 女生
    """
​
    gender_text = "男生"
​
    if not gender:
        gender_text = "女生"
​
    print("%s%s 是 %s" % (title, name, gender_text))
​
​
# 提示:在指定缺省参数的默认值时,应该使用最常见的值作为默认值!假设班上的同学,男生居多!

print_info("小明")
print_info("老王", title="班长")
print_info("小美", gender=False)
定义默认参数要牢记一点:默认参数必须指向不变对象!

Python学习笔记 之 函数进阶_递归_09

Python学习笔记 之 函数进阶_默认值_10

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

 

3.3 多值参数(知道)

定义支持多值参数的函数

  • 有时可能需要 一个函数 能够处理的参数 个数 是不确定的,这个时候,就可以使用 多值参数

  • python 中有 两种 多值参数:

    • 参数名前增加 一个 * 可以接收 元组

    • 参数名前增加 两个 * 可以接收 字典

  • 一般在给多值参数命名时,习惯使用以下两个名字

    • *args —— 存放 元组 参数,前面有一个 *

    • **kwargs —— 存放 字典 参数,前面有两个 *

  • argsarguments 的缩写,有变量的含义

  • kwkeyword 的缩写,kwargs 可以记忆 键值对参数

def demo(num, *nums, **person):

    print(num)
    print(nums)
    print(person)


# demo(1)
demo(1, 2, 3, 4, 5, name="小明", age=18, name1="小", age1=18)
def demo(num, *nums, **person):

    print(num)
    print(nums)
    print(person)


demo(1)

Python学习笔记 之 函数进阶_数据_11

 

提示:多值参数 的应用会经常出现在网络上一些大牛开发的框架中,知道多值参数,有利于我们能够读懂大牛的代码

多值参数案例 —— 计算任意多个数字的和

需求

  1. 定义一个函数 sum_numbers,可以接收的 任意多个整数

  2. 功能要求:将传递的 所有数字累加 并且返回累加结果

  3. def sum_numbers(*args):
    # def sum_numbers(args):
    
        num = 0
    
        print(args)
        # 循环遍历
        for n in args:
            num += n
    
        return num
    
    result = sum_numbers(1, 2, 3, 4, 5)
    # it will be wrong
    # resuts = sum_nemr(neum)
    print(result)
    
def sum_numbers(*args):
​
    num = 0
    # 遍历 args 元组顺序求和
    for n in args:
        num += n
​
    return num
​
print(sum_numbers(1, 2, 3))

元组和字典的拆包(知道)

  • 在调用带有多值参数的函数时,如果希望:

    • 将一个 元组变量,直接传递给 args

    • 将一个 字典变量,直接传递给 kwargs

  • 就可以使用 拆包,简化参数的传递,拆包 的方式是:

    • 元组变量前,增加 一个 *

    • 字典变量前,增加 两个 *

    • 要注意定义可变参数和关键字参数的语法:
      *args 是可变参数, args 接收的是一个 tuple;
      **kw 是关键字参数, kw 接收的是一个 dict。
       



def demo(*args, **kwargs):
	print(args)
	print(kwargs)

gl_nums = (1,2,3)
gl_dict = {"name":"michael", "age":25}

demo(gl_nums, gl_dict)

Python学习笔记 之 函数进阶_缺省参数_12



def demo(*args, **kwargs):
	print(args)
	print(kwargs)

gl_nums = (1,2,3)
gl_dict = {"name":"michael", "age":25}

demo(1,2,3,gl_nums, gl_dict)

Python学习笔记 之 函数进阶_数据_13

 



def demo(*args, **kwargs):
	print(args)
	print(kwargs)

gl_nums = (1,2,3)
gl_dict = {"name":"michael", "age":25}

demo(1,2,3,gl_nums, **gl_dict)

Python学习笔记 之 函数进阶_元组_14



def demo(*args, **kwargs):
	print(args)
	print(kwargs)

gl_nums = (1,2,3)
gl_dict = {"name":"michael", "age":25}

demo(*gl_nums, **gl_dict)

Python学习笔记 之 函数进阶_递归_15

 

def demo(*args, **kwargs):

    print(args)
    print(kwargs)


# 元组变量/字典变量
gl_nums = (1, 2, 3)
gl_dict = {"name": "小明", "age": 18}

# demo(gl_nums, gl_dict)

# 拆包语法,简化元组变量/字典变量的传递
demo(*gl_nums, **gl_dict)

demo(1, 2, 3, name="小明", age=18)

04. 函数的递归

函数调用自身的 编程技巧 称为递归

4.1 递归函数的特点

特点

  • 一个函数 内部 调用自己

    • 函数内部可以调用其他函数,当然在函数内部也可以调用自己

代码特点

  1. 函数内部的 代码 是相同的,只是针对 参数 不同,处理的结果不同

  2. 参数满足一个条件 时,函数不再执行

    • 这个非常重要,通常被称为递归的出口,否则 会出现死循环

示例代码

def sum_number(num):

    print(num)
    # 递归的出口,当参数满足某个条件时,不再执行函数
    if num == 1:
        return 

    # 自己调用自己
    sum_number(num - 1)

sum_number(3)

Python学习笔记 之 函数进阶_递归_16

Python学习笔记 之 函数进阶_默认值_17

 

 

4.2 递归案例 —— 计算数字累加

需求

  1. 定义一个函数 sum_numbers

  2. 能够接收一个 num 的整数参数

  3. 计算 1 + 2 + ... num 的结果

gl_sum = 0

def sum_numer(num):
	if num == 1:
		return 1
	else:
		return num + sum_numer(num-1)


resutl = sum_numer(100)
print(resutl)
# 定义一个函数 sum_numbers
# 能够接收一个 num 的整数参数
# 计算 1 + 2 + ... num 的结果


def sum_numbers(num):

    # 1. 出口
    if num == 1:
        return 1

    # 2. 数字的累加 num + (1...num -1)
    # 假设 sum_numbers 能够正确的处理 1...num - 1
    temp = sum_numbers(num - 1)

    # 两个数字的相加
    return num + temp


result = sum_numbers(100)
print(result)

 

提示:递归是一个 编程技巧,初次接触递归会感觉有些吃力!在处理 不确定的循环条件时,格外的有用,例如:遍历整个文件目录的结构

 

Python学习笔记 之 函数进阶_数据_18