python基础—-07函数

一、函数概述

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

xf(x)y
输入函数输出
参数函数返回值

比如在之前经常用到的
在这里插入图片描述
举例一些函数:

#all()函数,所有的输入值全为真时,返回True,当有一个为假时,返回False,相当于逻辑与and
result = all([True,True,False]) #参数:[True,True,False]
print(result)            # 返回值:result

#any()函数,输入全为假,返回False,输入有一个真,返回True,相当于逻辑或or
result = any([True,True,False])
print(result)

从实现函数的角度来看,其至少需要想清楚以下 3 点:
(1)函数需要几个关键的动态变化的数据,这些数据应该被定义成函数的参数
(2)函数需要传出几个重要的数据(就是调用该函数的人希望得到的数据),这些数据 应该被定义成返回值
(3) 函数的内部实现过程

二、函数的创建和调用

1、函数创建与调用:

定义函数,也就是创建一个函数,即创建一个具有某些用途的工具。
格式:def 函数名(参数1,参数2,…):

调用函数,也就是执行函数。如果把创建的函数理解为一个具有某种用途的工具,那 么调用函数就相当于使用该工具。
格式:函数名([形参值])

#创建函数
def mymax(num1,num2):
	return num1 if num1 > num2 else num2  #函数实现,即函数执行的内容

#调用函数
result = mymax(1,2)    #接收返回值
print(result)

进一步改进:可以在定义函数时指定函数的参数和返回值的类型

#创建函数
#num1需要传入整形,num2需要传入整形,返回值也是整形
def mymax(num1:int, num2:int) -> int:
#为了方便理解,可以在下面写清楚函数作用,以后可以使用help(mymax)查看帮助
"""
求两数的最大值
:param num1 : 第一个数值
:param num2 : 第二个数值
:return: 最大值
"""
return num1 if num1 > num2 else num2  #函数执行内容

#调用函数
result = mymax(1,2)    #接收返回值
print(result)

定义空函数:
定义一个什么事也不做的空函数,可以用 pass 语句;
pass 可以用来作为占位符,还没想好怎么写 函数的代码,就可以先放一个 pass ,让代码能运行起来。

def login(user:str, password:str) -> bool:
	#pass

login('root','123')

注意
(1)定义函数的时候,函数内部代码不会执行,只有在调用函数的时候,才会执行代码的内容。可以通过debug来进行演示
在这里插入图片描述
(2)当定义的函数没有返回值时,默认返回None

def login(user:str, password:str) -> bool:
    if user == 'root' and password =='123':
        print('login ok')
    else:
        print('login fail')


result = login('root','123')
print(result)

运行结果:
在这里插入图片描述

案例:

#华氏温度转为摄氏温度
def f2c(f):
    """
    将华氏温度转换为摄氏温度
    :param f:  华氏温度
    :return:  摄氏温度
    """
    c = (f - 32) / 1.8
    return f,c

if __name__ == '__main__':     #后面再说
    f,c = f2c(30)              #接收返回值
    print("%.1f华氏温度转化为摄氏温度为%.1f" %(f,c))  #30.0华氏温度转化为摄氏温度为-1.1

函数里面可以调用其他函数:

#打印图形
def printOneLine():
    """  打印一行图形 """
    print('*'*30)

def printNumLine(num:int):
    """  打印多行图形  """
    for count in range(num):
        printOneLine()

printNumLine(3)

运行结果:
在这里插入图片描述

#数学计算
def sum3Number(a,b,c):
    """求3个数的和"""
    return a+b+c

def average3Number(a,b,c):
    """求3个数的平均值"""
    sumResult = sum3Number(a,b,c)    #调用求和函数
    averageResult = sumResult / 3    #求平均值
    return averageResult

if __name__ == '__main__':
    result = average3Number(1,2,3)  #调用求平均值函数,传入实参
    print("平均值为:",result)   #平均值为: 2.0

二、变量作用域

1、局部变量

定义:
局部变量,就是在函数内部定义的变量 ,只在函数内部生效
不同的函数可以定义相同名字的局部变量,且各自使用不会产生影响
部变量的作用:
为了临时保存数据需要在函数中定义变量来进行存储

def save_money(money):
    """存钱"""
    allMoney = 100    #定义局部变量
    print("存钱前:",allMoney)
    allMoney += money
    print("存钱后:",allMoney)

def view_money():
    allMoney = 500  #定义局部变量
    print(allMoney)

if __name__ == '__main__':
    save_money(50)
    view_money()

运行结果:
在这里插入图片描述
可以看到,定义在save_money和view_money函数里的局部变量 allMoney 互不影响

2、全局变量

定义:
函数外边定义的变量叫做全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量。

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

allMoney = 100      #定义全局变量

def save_money(money):
    global allMoney     #使用全局变量之前通过global声明
    print("存钱前:",allMoney)
    allMoney += money
    print("存钱后:",allMoney)
    
def view_money():
    allMoney = 500   #定义局部变量
    print(allMoney)

if __name__ == '__main__':
    save_money(50)
    view_money()

运行结果:
在这里插入图片描述

3、如何将局部变量声明为全局变量

仍然使用 global 变量名

def save_money(money):
	global allMoney  #将局部变量声明为全局变量,这样,外部就可以访问到该局部变量
	allMoney = 100
	print("存钱前:",allMoney)
	allMoney += money
	print("存钱后:",allMoney)

4、可变数据类型和不可变数据类型

global的本质是声明可以修改全局变量的指向, 即变量可以指向新的数据。
1). 不可变类型的全局变量: 指向的数据不能修改, 修改该全局变量时,需要进行global声明
2). 可变类型的全局变量: 指向的数据可以修改, 修改该全局变量时,需要不进行global声明

Python 提供了如下三个工具函数来获取指定范围内的“变量字典”:
• globals():全局范围内所有变量组成的“变量字典”。
• locals(): 当前局部范围内所有变量组成的“变量字典”。
• vars(object):获取在指定对象范围内所有变量组成的“变量字典”。如果不 传入object 参数,vars() 和 locals() 的作用完全相同。

#定义两个全局变量
allMoney = 100
operator = []

def save_money(money):
    # allMoney是不可变数据类型,需要声明,operator是列表,是可变数据类型,不需要声明
    global allMoney
    print("存钱前:",allMoney,operator)
    allMoney += money
    operator.append("存钱%s" %(money))
    print("存钱后:",allMoney,operator)
    #locals() 当前局部范围内,所有变量组成”变量字典“
    print(locals())

if __name__ == '__main__':
    save_money(50)
    #globals() 全局范围内所有变量组成的”变量字典“
    #print(globals())

运行结果:
在这里插入图片描述

三、函数参数传递

1、实参与形参

形参:定义函数时小括号中的参数,用来接收参数用的
实参:调用函数时小括号中的参数,用来传递给函数用的

形参与实参的个数和类型要对应相等
如果个数不对应,会报错
但是如果类型不对应,python解释器无法检查出来,因此要进行数据类型检查
数据类型检查用内置函数 isinstance()

#这里 num1,num2是形参
def add(num1:int,num2:int) -> int:
    #数据类型检查
    if isinstance(num1,int) and isinstance(num2,int):
        return num1 + num2
    else:
        return -1

num1 = 1
num2 = 2
result = add(num1,num2) #这里 num1,num2是实参
print(result)   # 3

2、默认参数

默认参数可以降低调用函数的难度。
可变参数不能作为默认参数。

def mypow(x, y=2, z=None):
    """求次方,默认求2次方"""
    return x**y

if __name__ == '__main__':
    print(mypow(2))     # 4
    print(mypow(2,3))   # 8
def connect_mysql(user,password,host='localhost',port = 3306,charset = 'utf8'):
    print("connect mysql.....",user,password,host,port,charset)

if __name__ == '__main__':
    connect_mysql('root','redhat')

3、可变参数

可变参数就是传入的参数个数是可变的,用 *args
*args是形参,可以任意修改名称 :如 *nums
*args是可变参数,可以传入 1 个、2 个、3个…个参数
将所有的参数封装成元组,赋值给变量args

def square_sum(*args):
    print(args)

square_sum(1)
square_sum(1,2)
square_sum(1,2,3)

运行结果:
在这里插入图片描述

def square_sum(*nums):
    """求多个数的平方和"""
    result = 0
    for num in nums:    # *nums 是一个元组
        result = result + pow(num,2)
    return result

if __name__ == '__main__':
    result = square_sum(1,2,3)
    print(result)

可变参数解包

如果已经有一个 list 或者 tuple
要调用一个可变参数怎么办?
(1)Python 允许你在 list 或 tuple 前面加一个 * 号;
(2)把 list 或 tuple 的元素变成可变参数传进去;
例如:
一个元组 (1,2,3)
解包:*(1,2,3) -----> 1,2,3

def square_sum(*args):
    """求多个数的平方和"""
    result = 0
    for arg in nums:
        result = result + pow(narg,2)
    return result

#求100以内所有奇数的平方和    
#这里有一个元组nums,将它解包*nums 传入
nums = range(1,100,2)
result = square_sum(*nums)
print(result)      # 166650

4、关键字参数

关键字参数允许传入 0 个或任意个含参数名的参数;
这些关键字参数在函数内部自动组装为一个字典
关键字参数用 **kwargs
**kwargs是形参,名称可以任意修改

def student_info(name,age,**kwargs):
    print(name,age,kwargs)

#函数调用
student_info('xiaoming',10)
student_info('xiaohong',10,hobby = 'python program',city = '西安')

运行结果:
在这里插入图片描述

关键字参数解包

类似可变参数解包:
在list 或 tuple 前面加两个** 号

def student_info(name,age,**kwargs):
    print(name,age,kwargs)

info = {
    'hobby':'sing',
    'city':'上海'
}

student_info('xiaolan',10,**info) #将info解包传给kwargs

参数组合

形参(必选参数,默认参数,可变参数,关键字参数)
参数组合,即 必选参数、 默认参数、 可变参数和关键字参数一起使用。
参数定义的顺序必须是:必选参数、 默认参数、可变参数、关键字参数

四、匿名函数

1、定义:

匿名函数指一类无须定义标识符的函数或子程序。
Python用lambda语法定义匿名函数, 只需用表达式而无需声明。(省略了用def声明函数的标准步骤)
格式: lambda arg1,arg2… (形参): expression(函数)

lambda函数能接收任何数量的参数但只能返回一个表达式的值

mymax = lambda num1,num2:num1 if num1 > num2 else num2
print(mymax(1,2))     # 2

mypow = lambda x,y=2 : x**y
print(mypow(2))       # 4

2、应用场合

(1)函数作为参数传递
这里要说明一点:函数也可以赋值,比如:
abs(-1) #求绝对值
a = abs #将abs()函数赋给a ,则a和abs的功能一样
a(-1) #因此这里可以求绝对值

就是当有一个参数是函数时,这个函数可以用lambds写

def fun(num1, num2, operator_fun=pow):
    return  operator_fun(num1, num2)

print(fun(2, 3))
print(fun(2, 3, lambda  x, y: x+y))   #lambda作为参数传入

(2)作为内置函数的参数

一个例子说明:

#打印商品信息
from prettytable import  PrettyTable
def show(goods):
    """友好的以表格的方式打印商品信息"""
    table = PrettyTable(field_names=['Name', 'Count', 'Price'])
    for good in goods:
        table.add_row(good)
    print(table)

goods = [
    ("Python核心编程", 200, 378.9),
    ("Java核心编程", 300, 278.9),
    ("Php核心编程", 100, 78.9),
    ("Ruby核心编程", 260, 178.9),
]

print("按照数量进行排序".center(30, '*'))
#作为内置函数sort()的参数传入
goods.sort(key=lambda x:x[1]) #按元组里第一个索引排序
show(goods)

print("按照价格进行排序".center(30, '*'))
#作为内置函数sort()的参数传入
goods.sort(key=lambda x:x[2]) ##按元组里第二个索引排序
show(goods)

这里的,
x 表示 列表中的每一个元素:
(“Python核心编程”, 200, 378.9)
(“Java核心编程”, 300, 278.9)
(“Php核心编程”, 100, 78.9)
(“Ruby核心编程”, 260, 178.9)

x[1] 表示 列表里的每个元组里(上述元素)第一个索引
x[2] 表示 列表里的每个元组里(上述元素)第二个索引

运行结果:
在这里插入图片描述

#给定一个整形数组,将数组中所有的0移动到末尾,非0项保持不变
#在原始数组上进行移动操作,勿创建新的数组
li = [0, 7, 0, 2]
li.sort(key=lambda  x: 1 if x == 0 else 0)
print(li)

思路:
x表示列表中的每一个元素,如果元素等于0,将它赋值为1,如果元素不等于1,则赋值为0
这样根据[1,0,1,0]进行排序
即排序好为[7,2,0,0]

在这里插入图片描述

#有一个整数列表(10个元素),要求调整元素顺序,把所有的奇数放在前面,偶数放在后面
#与上一题同样的思路
list = [0,1,2,3,4,5,6,7,8,9]
list.sort(key = lambda x: 0 if (x % 2 != 0) else 1)
print(list)

五、递归函数

1、定义:

已知: 函数可以调用函数。
结论: 一个函数在内部调用自己本身,这个函数就是递归函数。
必须明确两点:
(1)递归退出的条件
(2)递归的规则

#递归计算阶乘
def factorial(num):
    """通过递归求阶乘"""
    #递归退出的条件: num <= 1
    #阶乘循环的内容: num! = num * (num - 1)!
    if num > 1:
        result = num *factorial(num-1)
    else:
        result = 1
    return result

if __name__ == '__main__':
   print(factorial(3))   # 6

2、案例

(1)递归实现斐波那契数列

斐波那契数列(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):
    #递归退出的条件: num = 1 或者 num = 2
    #递归的规则: F(num**)=F(num-1)+F(n**um-2)
    if num == 1 or num == 2:
        return 1
    else:
       return fib(num-1) + fib(num-2)

if __name__ == '__main__':
    print("第5个斐波那契数为:",fib(5))
    print("第7个斐波那契数为:", fib(7))

(2)递归实现汉诺塔问题

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

在这里插入图片描述
思路:

在这里插入图片描述
以n = 2为例:
移动的过程如图,三个塔分别命名:satrt,cache,start
分为三步,类似与把大象装进冰箱
把大象装进冰箱:
(1)把冰箱门打开
(2)把大象装进去
(3)关上冰箱门
在这里,n-1代表冰箱门,1代表大象
(1)先将n-1从start移动到cache(打开门)
(2)将1从start移动到target (把大象装进去)
(3)将n-1从cache移动到target(关上门)

movecount = 0
def hanoi(n,start='A',cache='B',target='C'):   #开始塔,缓存塔,目标塔 
    #递归退出条件: n=1
    #递归的规则:
    #第一步: 将n-1从start移动到cache,因此,此时的开始塔还是start,目标塔就变成了cache(先写出开始塔和目标塔的位置,剩下的那个是缓存) : hanoi(n-1,start,target,cache)
    #第二步: 将1从start移动到target,因此,此时的开始塔还是start,目标塔是target :  hanoi(1,start,cache,target)
    #第三步: 将n-1从cache移动到target,因此,此时的开始塔是cache,目标塔是target : hanoi(n-1,cache,start,target)
    if n == 1:
        print("盘子从%s移动到%s" %(start,target))
        global movecount
        movecount += 1
    else:
        hanoi(n - 1, start, target, cache)
        hanoi(1, start, cache, target)
        hanoi(n - 1, cache, start, target)

if __name__ == '__main__':
    hanoi(4)
    print("一共移动了%d次"%(movecount))

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值