Python 基础的核心——函数
文章目录
设计函数最为重要的原则: 单一职责原则(一个函数只做好一件事情)————> 高度内聚低耦合
high cohesion low coupling 一个函数做一件事
函数的定义
在Python中可以使用def
关键字来定义函数,和变量一样每个函数也应该有一个漂亮的名字,命名规则跟变量的命名规则是一致的。
且def
后还有():
括号里可以填参数 ,参数我们后面讲。
函数 —> y = f(x) / z = f(x, y) / … —> 相对独立且会被重复使用的功能(代码),将来想使用这些功能的时候,不需要再复制粘贴代码,而是直接通过调用函数来做到。
自变量(argument) —> 参数(parameter)
因变量 —> 返回值(return value)
参数,相当于输入的自变量
return
返回的是因变量
#定义函数:def是定义函数的关键字、ptp是函数名,data是参数(自变量)
def ptp(data):
return max(data) - min(data)
# return 返回的就是 极差
还可以对重复代码提取出来进行重构名
函数的注释
好的注释具有好的可读性,写好注释不做猪队友。
-
1、在第二行打上三给双引号回车后就成下面样子
-
2、然后对函数的作用进行说明
-
3、再对参数,和返回值进行说明
-
4、参数冒号后面是参数的类型,括号外面的是返回值的类型。
def ptp(data :list) -> int:
"""
求极差
:param data: 输入一个列表数据
:return: 返回极差
"""
return a + b
函数的参数
参数是函数中非常重要的结构
参数主要有
-
位置参数 : 参数在 * 号前对号入座即可 ,不用带参数名
-
可变参数 : 传入0个或任意多个参数
-
关键字参数 : 带参数名传入多个参数
当函数的参数个数无法确定时,我们可以利用下面两个关键字来接收参数
*args
可以接收零个或多个位置参数,将所有位置参数打包为一个元组。
**kwargs
可以接收零个或多个关键字参数 ,将所有的关键字参数打包为一个字典。
def add(*args,**kwargs):
"""
计算输入的值的和
:param args:
:param kwargs:
:return: 输入值求和
"""
total = 0
for arg in args:
if type(arg) in (int,float):
total += arg
for value in kwargs.values():
if type(value) in (int,float): #避免字符串带来的报错
total += value
return total
#由于args 和 kewargs 是位置参数与关键字参数
#如果不带参数名输入,其实就是由aegs接收的
#如果带得有参数名则是由kwargs参数接受的
#如果带有参数名 却 只用 args传入则会报错
#反之不带参数名 只用 kewargs 传入也会报错
print(add()) #0
print(add(1)) #1
print(add(1,b=2)) #3
print(add(1,b='2',c=3)) #4
print(add(1,b=2,c='hello',d=4)) #7
还有就是调用的时候未指定参数的值那么输出的结果是默认的
def ptp(a=3,b=2):
"""
求差
:param a: 输入一个数据
:param b
:return: 返回差
"""
return a-b
print(ptp()) #参数是默认的 结果为3-2=1
print(ptp(5,2)) #指定参数替代默认值 且对号入座 5-2=3
print(ptp(2,5)) #-3
全局变量和局部变量
-
Python程序中搜索一个变量是按照 LEGB 顺序进行搜索的
Local(局部作用域) —> Embeded(嵌套作用域) —> Global(全局作用域)
global
—> 声明使用全局变量或者定义一个局部变量将其放到全局作用域
nonlocal
—> 声明使用嵌套作用域的变量(不使用局部变量)
"""
全局变量和局部变量
全局变量(没有写在任何函数里面的变量)
局部变量(定义在函数内部的变量)
---> Built-in(内置作用域) ---> NameError: name ... not defined
global ---> 声明使用全局变量或者定义一个局部变量将其放到全局作用域
nonlocal ---> 声明使用嵌套作用域的变量(不使用局部变量)
"""
x = 100
def foo():
# 如果我不想在函数foo中定义局部变量x,想直接使用全局变量x,应该怎么做???
#global x
x = 200
def bar():
# 如果我不想在函数bar中定义局部变量x,想直接使用嵌套作用域中的x,应该怎么做???
#nonlocal x
x = 300
print(x) #300
bar()
print(x)#200
foo()
print(x) #100
#自己可以改变每个变量x的值 观察其输出情况
函数的高阶运用与lambda函数
在python中函数是一等函数(一等公民):
1.函数可以作为函数的参数,
2.函数可以作为函数的返回值
3.函数刻意赋值给变量
如果把函数作为函数的参数或者返回值,这种玩法称之为高阶函数
通常使用高阶函数可以实现对原有函数的解耦合操作。
运算 - operate,运算符 - operator
Lambda
函数 —> 没有名字而且一句话就能写完的函数,唯一的表达式就是函数的返回值
"""
example03 - 编写实现对列表元素进行冒泡排序的函数
设计函数的时候,一定要注意函数的无副作用性(调用函数不影响调用者)
Date: 2021/8/4
"""
def bubble_sort(items, ascending=True, gt=lambda x, y: x > y):
"""冒泡排序
:param items: 待排序的列表
:param ascending: 是否使用升序
:param gt: 比较两个元素大小的函数 可以降低代码耦合度
:return: 排序后的列表
"""
items = items[:]
for i in range(1, len(items)):
swapped = False
for j in range(0, len(items) - i):
if gt(items[j], items[j + 1]): #原代码式items[j] > items[j + 1] 现在把它改变
items[j], items[j + 1] = items[j + 1], items[j]
swapped = True
if not swapped:
break
if not ascending:
items = items[::-1]
return items
if __name__ == '__main__': #导入此模块的时候不会执行下列操作
# nums = [35, 96, 12, 78, 56, 64, 39, 80]
# print(bubble_sort(nums, ascending=False))
# print(nums)
#可以通过改变lambda 后面的关键字来替代代码中的表达式
words = ['apple', 'watermelon', 'hello', 'zoo', 'internationalization']
print(bubble_sort(words, gt=lambda x, y: len(x) > len(y), ascending=False))
函数的递归
函数可以自己调用自己
函数如果直接或间接的调用了自身,这种调用称为递归调用。
不管函数是调用别的函数,还是调用自身,一定要做到快速收敛。
在比较有限的调用次数内能够结束,而不是无限制的调用函数。
如果一个函数(通常指递归调用的函数)不能够快速收敛,那么就很有可能产生下面的错误
RecursionError: maximum recursion depth exceeded
最终导致程序的崩溃。
"""
阶乘的定义:
~ n! = n * (n - 1) * (n - 2) * ... * 2 * 1
~ n! = n * (n - 1)!
递归函数的两个要点:
1. 递归公式(第n次跟第n-1次的关系)
2. 收敛条件(什么时候停止递归调用)
Author:
Date: 2021/8/4
"""
def fac(num: int) -> int:
"""求阶乘(递归写法)"""
if num == 0:
return 1
return num * fac(num - 1)
if __name__ == '__main__':
# return 5 * fac(4)
# return 4 * fac(3)
# return 3 * fac(2)
# return 2 * fac(1)
# return 1 * fac(0)
# return 1
print(fac(5))