09 函数基础

目录

一、定义一个函数

 二、调用函数

 三、函数的参数

1.形参和实参

2. 参数的分类

3.参数默认值

4.参数类型说明

5.不定长参数

四、函数的返回值

 1.定义

2.关键字return

 五、变量的作用域

六、匿名函数

七、实参高阶函数 

1.定义

2.常见实参高阶函数

max、min、sorted、列表.sort

map(映射) 

filter(过滤)

 reduce(规约)

3.高阶函数和lambda函数的应用

 八、模块

1.定义与应用

2.导入模块

九、装饰器函数

十、函数的递归调用

十一、面向对象编程入门

综合案例 


函数是组织好的,封装功能上相对独立而且会被反复使用的代码,用来实现单一,或相关联功能的代码段。
如果我们将重复代码封装成函数,那么将来通过调用函数就能实现对代码的复用!!!

函数分为内置函数(已经写好的,例如print()、len())、自定义函数。这篇主要介绍自定义函数基础知识。

简单认识一下函数:

"""
example01 - 双色球 - 6个红色球+1个蓝色球
红色球:1-33 ---> 6
蓝色球:1-16 ---> 1实现机选n注的功能random.randint(a, b) ---> [a, b]
random.randrange(a, b) ---> [a, b)random.sample(population, k) ---> 无放回抽样 ---> list
random.choices(population, k) ---> 有放回抽样 ---> list
random.choice(population) ---> 随机抽出1个样本 ---> item
"""
import randomdef generate():"""生成一组随机双色球号码"""red_balls = [i for i in range(1, 34)]# random.sample(items, k) ---> []selected_balls = random.sample(red_balls, k=6)selected_balls.sort()# random.choices(items, k) ---> []# random.choice(items) ---> itemtemp = random.randrange(1, 17)selected_balls.append(temp)return selected_ballsdef display(balls):"""显示一组双色球号码"""# 输出红色球for ball in balls[:-1]:print(f'\033[31m{ball:0>2d}', end=' ')# 输出蓝色球print(f'\033[34m{balls[-1]:0>2d}')# 上面输出对控制端做了特殊设置,改变了字体颜色n = int(input('机选几注: '))
for _ in range(n):display(generate())

 

一、定义一个函数

函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号 : 起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None

注意:函数不一定有return,有没有取决于函数具体需不需要返回值。当没有return时,如果打印输出,函数也会默认返回None。

语法:

def 函数名(形参列表):函数说明文档函数体

说明:

def关键字;固定写法
函数名

由程序员自己命名
两个要求:是标识符;不是关键字
三个规范:

        见名知义(看到函数名就大概知道这个函数的功能)

        所有的字母都小写,单词和单词之间用下划线隔开
        不使用系统函数名、类名或者模块名

( )固定写法
形参列表

以'变量名1, 变量名2, 变量名3,...'的形式存在,这里的每一个变量就是一个形参
形参的作用:

将函数外部的数据传递到函数内部(用于提供通道的) 
如何确定形参:

看实现函数的功能需不需要额外的数据,如果需要就提供形参,需要多少个数据就给多少个形参

函数说明文档本质就是多行注释
函数体结构上,是和def保持一个缩进的一条或者多条语句(至少一条)
逻辑上,函数体就是实现函数功能的代码

 案例:

 

"""
example02 - 输入两个整数m和n(m >= n),计算组合数C(m, n)函数:封装功能上相对独立而且会被反复使用的代码
如果我们将重复代码封装成函数,那么将来通过调用函数就能实现对代码的复用!!!如果函数是现成的(Python标准库或三方库已经提供了该函数)就直接导入调用;
如果函数不是现成的,那么就需要我们自定义函数。组合 - combination
排列 - permutationy = f(x)bug - 臭屁虫、蛾子 - 计算机系统软硬件的缺陷或故障
debug - 调试
"""
from math import comb, perm# def fac(num):
#     result = 1
#     for i in range(2, num + 1):
#         result *= i
#     return result
#
#
# def comb(m, n):
#     """组合数"""
#     return fac(m) // fac(n) // fac(m - n)
#
#
# def perm(m, n):
#     """排列数"""
#     return fac(m) // fac(m - n)m = int(input('m = '))
n = int(input('n = '))
print('排列数: ', perm(m, n))
print('组合数: ', comb(m, n))
# math库中就有已经写好的排列组合函数,可以直接调用
"""
example03 - 输入x和y,求它们的最大公约数和最小公倍数最大公约数(greatest common divisor):x % z == 0 and y % z == 0 ---> 最大的z
最小公倍数(least common multiplier):z % x == 0 and z % y == 0 ---> 最小的z辗转求余数(欧几里得算法)15, 27 <----> 27, 15 <----> 15, 12 <----> 12, 3
x % y != 0
x, y = y, x % yas - alias - 别名
模块名.函数名 ---> 完全限定名(qualified name)
"""
from math import gcd, lcm# def gcd(x, y):
#     # 最大公约数
#     value_min = min(x, y)
#     for i in range(value_min, 0, -1):
#         if x % i == 0 and y % i == 0:
#             return i# def gcd(x, y):
#     # 最大公约数-辗转相除法/欧几里得算法
#     while x % y != 0:
#         x, y = y, x % y
#     return y
#
#
# def lcm(x, y):
#     return x * y // gcd(x, y)print(gcd(18, 6))
print(lcm(15, 27))

 二、调用函数

语法:

函数名(实参列表)

说明:

函数名必须是已经定义过的函数的函数名(需要哪个函数的功能就调用哪个函数,就写哪个函数的函数名)
( )固定写法
实参列表

实参就是从函数外部传递到函数内部的数据。
以'数据1, 数据2, 数据3,...'的形式存在

调用函数的时候提供的实参必须和定义函数的形参对应

函数调用的过程:
第一步:回到函数定义的位置
第二步:传参(用实参给形参赋值) - 传参的时候必须保证每个参数都有值
第三步:执行函数体
第四步:执行完函数体确定函数返回值
第五步:回到函数调用的位置接着往后执行

"""
example07 - 调用自定义函数"""
import randomimport matplotlib.pyplot as pltfrom example05 import mean, median, mode, ptp, std, vardef describe(data: list, func_names: list):"""输出描述性统计信息"""for name in func_names:print(f'{name}: ', end='')# Python 3.10+构造多分支结构 - math-casematch name.lower():case 'mean' | '均值': print(mean(data))case 'median' | '中位数': print(median(data))case 'mode' | '众数': print(mode(data))case 'max' | '最大值': print(max(data))case 'min' | '最小值': print(min(data))case 'ptp' | '极差': print(ptp(data))case 'pvar' | '总体方差': print(var(data, ddof=0))case 'var' | '方差' | '样本方差': print(var(data, ddof=1))case 'pstd' | '总体标准差': print(std(data, ddof=0))case 'std' | '标准差' | '样本标准差': print(std(data, ddof=1))case 'vc' | '变异系数': print(std(data) / mean(data))case _: print('无法完成对应的数据处理')# double underscore ---> dunder
if __name__ == '__main__':# 产生9个1-99均匀分布的随机数nums = [random.randint(1, 100) for _ in range(10)]print(nums)print(sorted(nums))describe(nums, ['MEAN', 'MEDIAN', 'VAR', 'xyz'])print('-' * 50)# 产生5000个均值为171标准差为6.5正态分布的随机数heights = [int(random.normalvariate(171, 6.5)) for _ in range(5000)]print(heights)describe(heights, ['均值', '众数', '最大值', '最小值', '极差', '标准差'])# 调用三方库的函数绘制直方图plt.hist(heights, bins=15)plt.show()

 三、函数的参数

1.形参和实参

对于函数来说,形式参数简称形参,是指在定义函数时,定义的一个变量名。

下面的代码中,x、y、z 就是形参。

#定义函数def foo(x, y, z):print("x=", x)print("y=", y)print("z=", z)#调用函数
foo(1,3,5)                #此处的1,3,5是实参

2. 参数的分类

根据实参提供方式的不同可以将实参分为位置参数和关键字参数两种

1)位置参数
调用函数的时候实参对应的数据直接写,让实参和形参从位置上一一对应

2)关键字参数
调用函数时以'形参名=数据'的方式来提供实参,实参和形参的对应关系由数据前面的形参名来决定

注意:调用同一个函数时位置参数和关键字参数可以一起使用,但是位置参数必须在关键字参数的前面

"""
example04 - 按要求编写函数实现相应的功能高内聚,低耦合 - high cohesion low coupling1. 编写一个函数判断输入的正整数是不是质数(只能被1和自身整除的数)
2. 开发一个生成指定长度的随机验证码的函数(要求:随机验证码由英文大小写字母和数字构成)
3. 编写一个函数输入三角形三条边的长度,计算三角形的面积(注意:三条边的长度不一定能构成三角形)"""
import math
import random
import string
# import time# from captcha import Captchadef is_prime(num):"""判断质数:param num: 待判断的正整数:return: 质数返回True,否则返回False"""for i in range(2, int(num ** 0.5) + 1):if num % i == 0:return Falsereturn Truedef random_code(*, length=4):"""随机验证码:param length: 验证码长度:return: 大小写英文字母和数字构成的字符串"""all_chars = string.ascii_letters + string.digitsreturn ''.join(random.choices(all_chars, k=length))def is_triangle(a, b, c):"""判断三条边能否构成三角形"""return a + b > c and b + c > a and a + c > b# 写在*后面的参数叫做(命名)关键字参数(keyword arguments),调用函数传入参数时必须带上参数名
# 写在/前面的参数叫做强制位置参数(positional-only arguments),调用函数传入参数时只能对号入座不能带参数名
# 既不在/前面也不在*后面的参数叫做位置参数,位置参数在传参时可以给参数名也可以对号入座,关键字参数必须放在位置参数之后
def area(a, b, c):"""用海伦公式计算三角形面积"""if is_triangle(a, b, c):h = (a + b + c) / 2return math.sqrt(h * (h - a) * (h - b) * (h - c))# 如果三条边的长度无效通过引发异常的方式提示函数的调用者raise ValueError('三条边长无法构成三角形')print(area(3, 1, 5))

3.参数默认值

定义函数的时候可以'形参名=数据'的方式给参数赋默认值,有默认值的形参在调用函数的时候可以不用传参
注意:如果一个函数有的参数有默认值有的参数没有默认值,没有默认值的参数必须在有默认值参数的前面。

4.参数类型说明

定义函数的时候指定参数类型

1)没有默认值的参数   -  在形参名后面加 ': 类型名'
2)给参数赋默认值,默认值对应的数据类型就是参数的类型

def func(x: str, y: int, z: list, t='', m: int = 10):pass

5.不定长参数

一个不定长参数可以同时接收若干实参

1)带 * 的不定长参数
在形参前面加 *,那么这个形参就会变成一个元组,它接受到的所有的实参会变成这个元组中的元素。
给带*号的不定长参数传参,只能使用位置参数

注意:如果带*的参数前后都有定长参数,*前面的定长参数只能用位置参数传参,*后面的定长参数只能用关键字参数传参  (记)

2)带**的不定长参数
在形参前面加 **,那么这个形参就会变成一个字典,它接收到的所有实参会变成这个字典中的键值对(实参必须是关键字参数)

四、函数的返回值

 1.定义

返回值就是函数内部传递到函数外部的数据。(函数内部产生的数据如果不通过返回值传递到函数外部,函数外部无法使用这个数据)
初学者建议:只要实现函数的功能产生了新的数据,都应该将新的数据作为返回值返回

1) 如何将数据从函数内部传递到函数外部(怎么确定函数返回值)
语法:return 需要返回的数据

注意:如果执行函数体的时候没有遇到return,函数的返回值就是 None(即函数也可以没有返回值,也就是没有return语句)

2) 如何在函数外部使用函数的返回值

函数调用表达式的值就是函数的返回值。
函数调用表达式: 调用函数的语句

2.关键字return

return只能在函数体中使用,有两个作用:
1)确定函数返回值
2)提前结束函数(执行函数体的时候,如果遇到return,函数直接结束)

 五、变量的作用域

变量的作用域指的是变量定义以后可以使用的范围,根据变量作用域的不同可以将变量分为全局变量和局部变量

1)全局变量

没有定义在函数或者类里面的变量就是全局变量,全局变量的作用域是从定义开始到程序结束。

2)局部变量

定义在函数中的变量就是局部变量,局部变量的作用域是从定义开始到函数结束。

3)变量存储的方式

全局变量默认保存在全局栈区间(全局栈区间在程序结束后才会自动释放),

局部变量保存在函数对应的临时栈区间中(每次调用函数的时候系统都会自动为这个函数创建一个临时栈区间,函数调用结束的时候这个栈区间会自动释放)

global关键字可以修改局部变量的保存方式,让局部变量保存到全局栈区间中。(global 变量名)

Python程序搜索一个标识符的时候会按照下面的顺序进行搜索:
局部作用域 ---> 嵌套作用域 ---> 全局作用域 ---> 内置作用域
local         embedded       global        built-in

global - 说明变量来自于全局作用域或者把一个局部变量放到全局作用域
nonlocal - 说明变量来自于嵌套作用域,如果嵌套作用域没有这个变量直接报错

x = 10  # 全局def foo():x = 100     # 局部def bar():x = 1000    # 嵌套print(x)bar()print(x)# print(y)foo()
print(x)

六、匿名函数

匿名函数的本质还是函数,除了定义方式和普通函数不同,其他的和普通函数一样。

语法:

函数名 = lambda 形参列表:返回值(或者说是表达式)

 注意:只有一句代码就可以实现功能的函数可以使用匿名函数

# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 ))    # 30
print ("相加后的值为 : ", sum( 20, 20 ))    # 40

七、实参高阶函数 

1.定义

参数是函数的函数就是实参高阶函数,给实参高阶函数传参的时候可以使用普通函数的函数名也可以使用匿名函数(内置函数都是高等函数)

注意:函数作为函数的参数时,不要跟圆括号调用函数,只是把函数的名字传入即可

2.常见实参高阶函数

max、min、sored、列表.sort、map、reduce、filter

max、min、sorted、列表.sort

 max(容器, *, key:函数)

说明:
         max(容器, 函数)   -  按照函数制定的规则比较容器中元素的大小来获取最大值
         函数的要求:1)有且只有一个参数,这个参数代表前面容器中的每个元素
                               2)有一个返回值,返回值就是比较对象

nums = [90, 78, 67, -92, 56, -71]# 案例1:求nums中元素的最大值
print(max(nums, key=lambda item: item))# 案例2:求nums中绝对值最大的元素
print(max(nums, key=lambda item: abs(item)))# 案例3:求students中分数最高的元素
students = [{'name': '张三', 'score': 38, 'age': 18},{'name': '小明', 'score': 99, 'age': 25},{'name': '李四', 'score': 89, 'age': 19},{'name': '老王', 'score': 70, 'age': 30},{'name': '小花', 'score': 65, 'age': 26}
]
print(max(students, key=lambda item: item['score']))# 练习1:求nums中个位数最小的元素
nums = [90, 78, 67, 92, 56, 71]
print(min(nums, key=lambda item: item % 10))# 练习2:将names中的名字按照长度最小到大到排序
names = ['李小名', '张三', '古丽热巴', '小花', '王大富']
names.sort(key=lambda item: len(item))
print(names)# 练习3:求students中年龄最大的学生
students = [{'name': '张三', 'score': 38, 'age': 18},{'name': '小明', 'score': 99, 'age': 25},{'name': '李四', 'score': 89, 'age': 19},{'name': '老王', 'score': 70, 'age': 30},{'name': '小花', 'score': 65, 'age': 26}
]
print(max(students, key=lambda item: item['age']))

map(映射) 

基于原容器中的元素创建一个新的容器

1)map(函数, 容器)     -   根据函数制定的规则将容器中的元素变成一个新的容器
      函数的要求:a.有且只有一个参数,代表容器中的每个元素
                            b.需要一个返回值,返回值就是新容器中的元素

2)map(函数, 容器1, 容器2)
      函数的要求:a.有且只有两个参数,分别代码后面两个容器中的元素
                            b.需要一个返回值,返回值就是新容器中的元素

3)map(函数, 容器1, 容器2, 容器3, ....)

# 案例1:创建一个新的容器,容器中的元素是nums中的元素乘以10的结果
nums = [19, 45, 1, 90, 67]
# [190, 450, 10, 900, 670]
result = map(lambda item: item * 10, nums)
print(list(result))# 案例2:将nums1和nums2中的元素相加(相同位置上的元素相加)
nums1 = [10, 20, 30, 40, 50]
nums2 = [2, 3, 5, 3, 2]
result = list(map(lambda item1, item2: item1 + item2, nums1, nums2))
print(result)# 练习1:提取nums中所有元素的个位数
nums = [19, 108, 44, 37, 82, 91, 86]
# [9, 8, 4, 7, 2, 1, 6]
result = map(lambda item: item % 10, nums)
print(list(result))# 练习2:将scores中分数转换成对应及格关系True或者False
scores = [90, 56, 89, 99, 45, 34, 87]
# [True, False, True, True, False, False, True]
result = map(lambda item: item >= 60, scores)
print(list(result))# 练习3:将scores中的分为转换成对应的通过关系
scores = [90, 56, 89, 99, 45, 34, 87]
# ['通过', '不通过', '通过', ....]
result = map(lambda item: '不通过' if item < 60 else '通过', scores)
print(list(result))# 练习4:将nums1中是元素的个位数作为新容器中元素的十位数,nums2中元素的十位数作为新容器中元素的个位数
nums1 = [89, 34, 89, 20, 192, 93]
nums2 = [102, 89, 37, 82, 26, 1293]
# [90, 48, 93, 8, 22, 39]
result = map(lambda i1, i2: i1 % 10 * 10 + i2 // 10 % 10, nums1, nums2)
print(list(result))result = map(lambda i1, i2: int(str(i1)[-1] + str(i2)[-2]), nums1, nums2)
print(list(result))

filter(过滤)

获取容器中所有满足条件的元素(筛选)

filter(规则, 容器数据:list...)

规则是指传入函数名来当规则的,即不加括号(不调用),而用filter来调用 

函数的要求:1)有且只有一个参数,代码容器中的每个元素
                      2)需要一个返回值,返回值对应的就是提取条件

# 案例1:提取nums中所有的偶数
nums = [19, 108, 44, 37, 82, 91, 86]
result = filter(lambda item: item % 2 == 0, nums)
print(list(result))     # [108, 44, 82, 86]# 提取nums中所有大于50的元素
result = filter(lambda item: item > 50, nums)
print(list(result))# 案例2:提起scores中所有不及格的分数
scores = [90, 56, 89, 99, 45, 34, 87]
result = filter(lambda item: item < 60, scores)
print(list(result))# 案例3:提取所有不及格的学生
students = [{'name': '张三', 'score': 38, 'age': 18},{'name': '小明', 'score': 99, 'age': 25},{'name': '李四', 'score': 89, 'age': 19},{'name': '老王', 'score': 50, 'age': 30},{'name': '小花', 'score': 65, 'age': 26}
]
result = filter(lambda stu: stu['score'] < 60, students)
print(list(result))# 练习1:提取字符串中所有的中文字符
str1 = 'sjs健康os02-技术上ss=2e 块'
result = filter(lambda char: '\u4e00' <= char <= '\u9fa5', str1)
print(''.join(result))

 reduce(规约)

将容器中的元素合并成一个值

reduce(函数, 容器, 初始值)     -   将容器中的元素按照函数制定的规则合并一个数据
函数的要求:1)有且只有两个参数,第一个指向初始值,第二个指向容器中的每个元素
                      2)  需要一个返回值,就是合并规则
注意:reduce使用的时候需要从functools中导入

from functools import reducenums = [2, 3, 4, 5, 1]
# 2+3+4+5+1
result = reduce(lambda i, item: i + item, nums, 0)
print(result)# 2*3*4*5*1
result = reduce(lambda i, item: i * item, nums, 1)
print(result)# 23451
# '' + '2' + '3' + '4' + '5' + '1'  -> '' + str(2) + str(3) + ...
result = reduce(lambda i, item: i + str(item), nums, '')
print(result)# 练习1: 求nums中所有元素的个位数的和
scores = [90, 56, 89, 99, 45, 34, 87]
result = reduce(lambda i, item: i + item % 10, scores, 0)
print(result)# 练习2:求students中所有学生的总成绩
students = [{'name': '张三', 'score': 38, 'age': 18},{'name': '小明', 'score': 99, 'age': 25},{'name': '李四', 'score': 89, 'age': 19},{'name': '老王', 'score': 50, 'age': 30},{'name': '小花', 'score': 65, 'age': 26}
]
result = reduce(lambda i, stu: i + stu['score'], students, 0)
print(result)

3.高阶函数和lambda函数的应用

 sorted(list, key, reverse) - key参数可以传入一个函数指定比较元素大小的规则

# 按照股票价格从高到低输出股票代码和股票价格
prices = {'AAPL': 191.88,'GOOG': 1186.96,'IBM': 149.24,'ORCL': 48.44,'ACN': 166.89,'FB': 208.09,'SYMC': 21.29
}
# sorted_keys = sorted(prices, key=prices.get, reverse=True)
sorted_keys = sorted(prices, key=lambda x: prices[x], reverse=True)
for key in sorted_keys:print(f'{key}: {prices[key]}')# 按照字符串的长度从短到长对列表进行排序
words = ['apple', 'banana', 'zoo', 'no', 'watermelon', 'internationalization', 'over']
print(sorted(words, key=len, reverse=True))

 

 八、模块

1.定义与应用

python中的一个.py文件就是一个模块。

应用前提:

被使用的模块的模块名必须符合变量名的要求;并且导入后才能使用

2.导入模块

1) import 模块名

导入指定模块,导入后可以通过'模块名.xxx'的方式去使用这个模块中的所有内容

2) from 模块名 import 内容1, 内容2, 内容3, ...

导入指定模块,导入后可以直接使用指定的内容

3) from 模块名 import *

导入指定模块,导入后可以直接使用模块中所有内容

4) import 模块名 as 新模块名

对导入的模块进行重命名

5) from 模块名 import 内容 as 新内容名

九、装饰器函数

装饰器:用一个函数去装饰另外一个函数并为其提供额外的能力(跟正常业务没有必然联系的功能)。
装饰器实现了设计模式中的代理模式。

装饰器函数的参数是被装饰的函数,装饰器函数的返回值是带有装饰功能的函数(不仅要执行原函数还要执行额外的操作)。
很显然,装饰器函数是高阶函数的用法。

语法:

def decorator_function(original_function):def wrapper(*args, **kwargs):# 这里是在调用原始函数前添加的新功能before_call_code()result = original_function(*args, **kwargs)# 这里是在调用原始函数后添加的新功能after_call_code()return resultreturn wrapper# 使用装饰器
@decorator_function
def target_function(arg1, arg2):pass  # 原始函数的实现

案例1:

from functools import wraps# 装饰器函数
def titlize_string(func):# *args可变参数,**kwargs可变关键字参数# *args - 将传入的位置参数打包成一个元组# **kwargs - 将传入的关键字参数打包成字典@wraps(func)def wrapper(*args, **kwargs):result = func(*args, **kwargs)# if type(result) == str:if isinstance(result, str):n = len(result)result = '~' * n + '\n' + result.title() + '\n' + '~' * nreturn resultreturn wrapper@titlize_string
def f1():return 'hello, world!'# f1 = titlize_string(f1)
print(f1())

 案例2:

import random
import timefrom functools import wrapsdef random_delay(lower, upper):"""随机延迟指定范围的秒数"""duration = random.random() * (upper - lower) + lowertime.sleep(duration)def record_time(func):@wraps(func)def wrapper(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time()print(f'Time elapsed: {end - start:.3f}s')return resultreturn wrapper# download = record_time(download)
@record_time
def download(filename):"""下载文件"""print(f'开始下载"{filename}".')random_delay(3, 8)print(f'"{filename}"下载完成.')# upload = record_time(upload)
@record_time
def upload(filename):"""上传文件"""print(f'开始上传"{filename}".')random_delay(5, 10)print(f'"{filename}"上传完成.')download('MySQL从删库到跑路.avi')
upload('Python从入门到住院.pdf')
# 取消装饰器(执行原函数 - 被装饰前的download函数)
download.__wrapped__('MySQL从删库到跑路.avi')

十、函数的递归调用

函数的递归(recursion)调用

1. 递归公式 - 第n次跟第n-1、n-2、……次之间的关系
2. 收敛条件 - 什么时候停止递归

from functools import lru_cachedef fac(num):if num == 0:return 1return num * fac(num - 1)# lru - least recently used - 缓存置换策略
# cache - 缓存
@lru_cache(maxsize=128)
def fib(n):if n in (1, 2):return 1return fib(n - 1) + fib(n - 2)def main():for n in range(0, 10):print(f'{n}! = {fac(n)}')print('-' * 20)for n in range(1, 121):print(f'{n:0>3d}: {fib(n)}')if __name__ == '__main__':main()

案例:

"""
example15 - 一个小孩爬楼梯,一次可以爬一个、两个或三个台阶,
问:走完10个台阶一共有多少种走法?"""
# from functools import lru_cache# @lru_cache(maxsize=64)
# def climb(n):
#     if n < 0:
#         return 0
#     elif n == 0:
#         return 1
#     return climb(n - 1) + climb(n - 2) + climb(n - 3)# 调用函数会得到一个生成器对象
def climb(n):a, b, c, d = 0, 1, 2, 4for _ in range(n):a, b, c, d = b, c, d, b + c + dyield a# # 生成器对象
# gen = climb(30)
# # 通过next函数从生成器中获取数据
# # print(next(gen))
# # 将生成器直接放到for-in循环中
# for value in gen:
#     print(value)
#
# print('~' * 30)
#
# # 循环体一次都不会执行
# # 因为生成器的数据已经被取走无法再提供任何数据
# for value in gen:
#     print(value)# generator expression - 生成器表达式
x = (i ** 2 for i in range(1, 10))
print(x)  # 生成器对象 - 惰性计算(拿一个算一个给一个)
print(type(x))  # generatorprint(next(x))
print(next(x))
print(next(x))
print(next(x))print('~' * 30)for v in x:print(v)

十一、面向对象编程入门

对象:接收消息的实体(一组数据和处理数据的方法构成的整体)- 具体
    ~ 一切皆为对象
    ~ 对象都有属性(数据)和行为(函数)
    ~ 对象一定属于某个类
类:创建对象的蓝图和模板(行为相同的对象可以归纳成一个类)- 抽象
    ~ 数据抽象 - 找到一类对象共同的属性(静态特征)
    ~ 行为抽象 - 找到一类对象共同的行为(动态特征)

流程:定义类 ----> 创建对象 ----> 给对象发消息

继承:从已有的类创建新类的过程,提供继承信息的叫做父类(超类),得到继承信息的叫做子类(派生类)is-a关系

class Person:def __init__(self, name, age):self.name = nameself.age = agedef eat(self, food_name):print(f'{self.name}正在吃{food_name}')def sleep(self):print(f'{self.name}正在睡觉')class Student(Person):def study(self, course_name):print(f'{self.name}正在学习{course_name}')class Teacher(Person):def __init__(self, name, age, title):super().__init__(name, age)self.title = titledef teach(self, course_name):print(f'{self.name}{self.title}正在讲授{course_name}')class Programmer(Person):def __init__(self, name, age, level):super().__init__(name, age)self.level = level# override - 方法重写 - 子类把父类已有的方法重新实现一遍def sleep(self):# super().sleep()  # 调用父类的sleep方法print(f'{self.name}每天只睡两个小时')def write_code(self, language):print(f'{self.name}正在用{language}写屎山代码')class DataAnalyst(Person):def __init__(self, name, age, year):super().__init__(name, age)self.year = yeardef analyse_data(self):print(f'{self.name}正在从数据中发掘商业价值')# 2. 创建对象 - 构造器语法
stu1 = Student('骆昊', 44)
stu2 = Student('王大锤', 20)
teacher = Teacher('张三丰', 100, '教授')# 3. 给对象发消息
stu1.eat('方便面')
stu2.study('Python程序设计')
stu2.sleep()
teacher.sleep()
teacher.teach('太极拳')programmer = Programmer('狄仁杰', 38, 10)
programmer.sleep()
programmer.write_code('Java')

 上面先定义了一个Person()的类,在Person类里面定义了相应的属性和方法,然后又通过继承Person类定义了Student(Person)、Teacher(Person)等类,在类里又有相应只属于自己类的方法,同时继承了Person的类又一定包含Person类里的方法和属性。

练习1:

定义一个时钟类,有时、分、秒三个属性,同时有显示、走针两种方法。

class Clock:def __init__(self, hour=0, minute=0, second=0):self.hour = hourself.minute = minuteself.second = seconddef show(self, display_second=True):result = f'{self.hour:0>2d}:{self.minute:0>2d}'if display_second:result += f':{self.second:0>2d}'return resultdef run(self):self.second += 1if self.second == 60:self.second = 0self.minute += 1if self.minute == 60:self.minute = 0self.hour += 1if self.hour == 24:self.hour = 0clock = Clock(23, 58, 58)
while True:# windows# os.system('cls')# macOSos.system('clear')print(clock.show())clock.run()time.sleep(1)

 练习2:

"""1. 定义一个类描述平面上的点,提供移动点和计算到另一个点的距离的方法
2. 定义一个类描述平面上的线段,提供计算线段长度和斜率的方法
思考:这个类之间又没有什么关系??? has-a关系 - 关联关系"""
import mathclass Point:"""平面上的点"""def __init__(self, x, y):self.x = xself.y = ydef move_to(self, x, y):"""移动到指定的位置"""self.x = xself.y = ydef move_by(self, dx, dy):"""移动指定的偏移量"""self.x += dxself.y += dydef distance(self, other):"""计算到另一个点的距离"""return math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2)class Line:"""平面上的线段"""def __init__(self, start: Point, end: Point):self.start = startself.end = end@propertydef length(self):"""长度"""return self.start.distance(self.end)@propertydef slope(self):"""斜率"""return (self.end.y - self.start.y) / (self.end.x - self.start.x)p1 = Point(2, 3)
p2 = Point(-5, 6)
print(p1.distance(p2))
p2.move_by(10, 1)
print(p1.distance(p2))line = Line(p1, p2)
print(line.length)
print(line.slope)

面向对象编程应用:

"""
example20 - 面向对象编程案例:扑克游戏 - 牌、扑克、玩家类:创建对象的蓝图和模板(对象的共性抽取出来)~ 数据抽象 - 属性 - 静态特征~ 行为抽象 - 方法 - 动态特征
对象:类实例化以后就是对象,对象是可以接收消息的实体~ 一切皆为对象~ 每个对象都是独一无二的~ 对象都有属性和行为~ 对象都属于某个类三大支柱:~ 封装(encapsulation):隐藏实现细节,暴露简单的调用接口~ 继承(inheritance):从已有的类创建新类的过程,提供继承信息的叫父类,得到继承信息的叫子类~ 多态(polymorphism):子类可以重写(override)父类的方法,不同的子类在接收到相同的消息时会表现出不同的行为Spade / Heart / Club / Diamond面试官:讲一讲Python中的迭代器和生成器,二者是什么关系?
参考答案:Python中的迭代器是实现了迭代器协议的对象,迭代器协议是两个魔术方法,一个叫__iter__,一个叫__next__。
如果一个类里面有__next__和__iter__两个魔术方法,那么该类的对象是迭代器对象。
生成器是迭代器语法简化升级之后的版本,生成器就是迭代器,只不过创建生成器的语法更加简单。"""
import itertools
import randomclass Card:"""牌"""def __init__(self, suite, face):self.suite = suiteself.face = face# less thandef __lt__(self, other):if self.face == other.face:return self.suite < other.suitereturn self.face < other.face# representationdef __repr__(self):suites = ['♠️', '❤️', '♣️', '♦️']faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']return f'{suites[self.suite]}{faces[self.face]}'class Poker:"""扑克"""def __init__(self):self.position = 0self.cards = [Card(suite, face)for suite, face in itertools.product(range(4), range(1, 14))]def shuffle(self):"""洗牌"""self.position = 0random.shuffle(self.cards)# self.cards = random.sample(self.cards, k=len(self.cards))def __iter__(self):return selfdef __next__(self):if self.has_more():card = self.cards[self.position]self.position += 1return cardraise StopIteration()def has_more(self):"""有没有牌可以发出"""return self.position < len(self.cards)class Player:"""玩家"""def __init__(self, nickname):self.nickname = nicknameself.cards = []def get_one(self, card):"""摸牌"""self.cards.append(card)def arrange(self):"""整理"""self.cards.sort()def main():"""入口函数"""poker = Poker()poker.shuffle()players = [Player('骆昊'), Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]for _ in range(3):for player in players:card = next(poker)player.get_one(card)for player in players:player.arrange()print(player.nickname, end=': ')print(player.cards)if __name__ == '__main__':main()

 

综合案例 

"""
example05 - 假设样本数据保存一个列表中,设计获取样本数据描述性统计信息的函数经验:函数的设计一定要做到无副作用!!!描述性统计信息 - 集中趋势、离散程度、分布规律~ 集中趋势:均值、中位数、众数~ 离散程度:极值、极差(全距)、方差、标准差、变异系数~ 分布规律:直方图、偏态系数、峰度系数1. 均值
2. 中位数
3. 极差
4. 样本方差
5. 样本标准差
"""
import math
import random
import statistics as statsdef mean(data: list):"""算术平均"""return sum(data) / len(data)def median(data: list):"""中位数"""data, n = sorted(data), len(data)if n % 2 == 0:return mean(data[n // 2 - 1: n // 2 + 1])return data[n // 2]def mode(data: list):"""众数"""results = {}for x_i in data:results[x_i] = results.get(x_i, 0) + 1return max(results, key=results.get)def ptp(data: list):"""极差(全距)"""return max(data) - min(data)# delta degree of freedom - 损失的自由度
def var(data: list, *, ddof=1) -> float:"""variance 方差ddof = 1,求样本方差,函数默认为1ddof = 0,求总体方差ddof为关键字参数"""x_bar, n = mean(data), len(data)return sum([(x_i - x_bar) ** 2 for x_i in data]) / (n - ddof)def std(data: list, *, ddof=1) -> float:"""标准差"""return math.sqrt(var(data, ddof=ddof))# __name__ 是模块的一个隐藏属性,代表这个模块的名字
# 如果你直接调用Python解释器运行某个模块,它的名字一定叫 __main__
# 如果你在其他模块导入这个模块,这个时候它的名字就是文件名(example05)
if __name__ == '__main__':random.seed(1)nums = [random.randint(1, 100) for _ in range(10)]print(nums)print(sorted(nums))print('均值:', mean(nums))print('均值:', stats.mean(nums))print('中位数:', median(nums))print('中位数:', stats.median(nums))print('众数:', mode(nums))print('众数:', stats.mode(nums))print('极差:', ptp(nums))print('样本方差:', var(nums))print('样本方差:', stats.variance(nums))print('样本方差:', var(nums, ddof=0))print('样本方差:', stats.pvariance(nums))print('样本标准差:', std(nums))print('样本标准差:', stats.stdev(nums))print('总体标准差:', std(nums, ddof=0))print('总体标准差:', stats.pstdev(nums))
"""
example10 - 练习:设计一个函数,传入两组数据,计算两组数据的相关系数"""
import mathimport matplotlib.pyplot as pltfrom example05 import meandef corr(X, Y):"""计算两组数据的皮尔逊相关系数"""x_bar, y_bar = mean(X), mean(Y)temp1 = sum([(x_i - x_bar) * (y_i - y_bar) for x_i, y_i in zip(X, Y)])temp2 = math.sqrt(sum([(x_i - x_bar) ** 2 for x_i in X]))temp3 = math.sqrt(sum([(y_i - y_bar) ** 2 for y_i in Y]))return temp1 / (temp2 * temp3)if __name__ == '__main__':incomes = [25000, 15850, 15500, 20500, 22000, 20010, 26050, 12500, 18500, 27300,13300,  8300, 23320,  5250,  5800,  9100,  4800, 16000, 28500, 32000,31300, 10800,  6750,  6020, 15000, 30020,  3200, 17300,  8835,  3500]payments = [2599, 1400, 1120, 2560, 1900, 1200, 2320,  800, 1650, 2200,1200,  580, 1885,  600,  400,  800,  420, 1380, 1980, 3999,3800,  725,  520,  420,  980, 4020,  350, 1500,  560,  500]# Excel - CORREL(A1:A30, B1:B30)函数print(corr(incomes, payments))# 绘制散点图 - 定性分析两组数据的相关性plt.scatter(incomes, payments)plt.show()

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/871860.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10.1 JSP语言入门

JSP语言入门 目录一、 基础概念1. 什么是JSP&#xff1f;2. 工作原理3. 基本语法 二、 表达式语言&#xff08;EL&#xff09;1. 简介2. 语法 三、 JSTL&#xff08;JSP Standard Tag Library&#xff09;1. 简介2. 核心标签库3. 常用标签 四、 高级话题1. 会话管理2. 自定义标…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(十一)-无人机服务可用性用例需求

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

Python:while循环

while循环体 while 条件: 符合条件执行语句 .... 执行完后需执行的语句 # while循环 i1 while i<5:print(i)ii1 print("Done") test. 做一颗圣诞树吧 答案&#xff1a; # while循环 i 1 j5 while i < 5:print( * j* * i)i i 2jj-1 print("Done"…

护佑未来!引领儿童安全新时代的AI大模型

引领儿童安全新时代的AI大模型 一. 前言1.1 AI在儿童安全方面的潜在作用1.2 实时监控与预警1.3 个性化安全教育与引导1.4 家长监护与安全意识提升 二. AI大模型的优势2.1. 保护儿童隐私和安全的重要性2.2. AI大模型如何应用于儿童安全领域2.1 儿童内容过滤2.2.1 儿童行为监测 2…

代码检查规则语言CodeNavi中代码语句的节点和节点属性

本文分享至华为云社区《CodeNavi 中代码语句的节点和节点属性》。作者&#xff1a;Uncle_Tom 1. 前期回顾 《寻找适合编写静态分析规则的语言》 根据代码检查中的一些痛点&#xff0c;提出了希望寻找一种适合编写静态分析规则的语言。 可以满足用户对代码检查不断增加的各种需求…

使用 PyAMF / Django 实现 Flex 类映射

1、问题背景 PyAMF 是一个用于在 Flex 和 Python 之间进行通信的库&#xff0c;在使用 PyAMF 与 Flex 应用进行通信时&#xff0c;经常会遇到错误。例如&#xff0c;在发送一个 Flex Investor 对象到 Python 时&#xff0c;会得到一个 ‘KeyError: first_name’ 的错误。这是因…

DevToys-开源免费开发工具箱

个人觉得相较于那些在线的工具箱&#xff0c;这种离线的工具箱客户端更加可信一些。 DevToys 提供了30 个默认工具&#xff1a; 转换器&#xff1a;JSON <> YAML、日期、数字基数......编码器/解码器&#xff1a;HTML、URL、Base64、GZip、JWT、二维码......格式化程序…

如何理解LTI系统的线性相位和群延迟

原文出自微信公众号【小小的电子之路】 在信号处理领域&#xff0c;经常会提到两个名词-线性相位与群延迟&#xff0c;那么&#xff0c;什么是线性相位&#xff1f;什么是群延迟&#xff1f;二者之间又有什么关系呢&#xff1f; 一、理论原理 1、线性相位 对于线性时不变系统…

[BJDCTF2020]EzPHP1

知识点&#xff1a;1. url编码绕过 2. %0a绕过 3. post优先级绕过 4. php伪协议 5. 数组的强类型比较绕过 6. 取反绕过 进入之后发现了一个很帅气的页面&#x1f60e;~ 看看网页源代码试试~ 是base32编码&#xff0c;尝试一下解码. https://www.qqxiuzi.cn/bianma/base.php 解…

SpringBoot+Vue实现简单的文件上传(Excel篇)

SpringBootVue实现简单的文件上传 1 环境 SpringBoot 3.2.1&#xff0c;Vue 2&#xff0c;ElementUI 2 页面 3 效果&#xff1a;只能上传xls文件且大小限制为2M&#xff0c;选择文件后自动上传。 4 前端代码 <template><div class"container"><el…

Java---类与对象(二)

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 文章目录 封装访问限定符&#xff08;重点&#xff0…

基于springboot 大学校园拼够系统设计与实现

摘 要 大学校园拼购系统是为了方便用户能够在网站上查看校园拼购、公告信息等&#xff0c;于是开发了基于springboot框架设计与实现了一款简洁、轻便的大学校园拼购系统。本系统解决了大学校园拼购管理事务中的主要问题&#xff0c;包括以下多个功能模块&#xff1a;商家、用户…

Golang | Leetcode Golang题解之第229题多数元素II

题目&#xff1a; 题解&#xff1a; func majorityElement(nums []int) (ans []int) {cnt : map[int]int{}for _, v : range nums {cnt[v]}for v, c : range cnt {if c > len(nums)/3 {ans append(ans, v)}}return }

找到完美的横道图工具:2024年选择指南

国内外主流的10款项目进度横道图软件对比&#xff1a;PingCode、Worktile、灵动计划&#xff08;Wolai&#xff09;、飞书项目、Tapd、麦客CRM、Asana、Trello、Smartsheet、Basecamp。 在管理项目时&#xff0c;确保所有进度和任务都按计划进行是每个项目经理面临的一大挑战。…

WordPress:无法创建新文章?创建新帖子时候页面空白

wordPress中我们新建文章的时候&#xff0c;会遇到页面空白&#xff0c;这个问题是怎么导致呢&#xff1f;我们可以打开F12开发者模式看下报错信息&#xff0c;这是一个警告信息 Warning: Creating default object from empty value in /pub 到数据库 wp_posts中查看生成了很…

漏洞挖掘 | 记某证书站任意账号接管漏洞

下文中所述漏洞已修复 在前段时间的漏洞挖掘中&#xff0c;上了某证书站&#xff0c;打点的一处逻辑漏洞 访问某一站点&#xff0c;发现了一处登录页 点击登录按钮之后&#xff0c;发现该站点大概率是自写站点&#xff0c;存在逻辑漏洞的可能性大大增大&#xff0c;利用前期信…

CentOS7配置阿里云yum源

前提&#xff1a;确认机器可以连接互联网&#xff0c;且系统已经安装了wget软件 先进入到/etc/yum.repos.d目录下查看是否有原来的yum源配置文件&#xff0c;如果有&#xff0c;就将它们备份一下 用yum repolist命令测试&#xff0c;当前系统已经没有可用yum源 输入命令wget -…

Java二十三种设计模式-建造者模式(4/23)

建造者模式&#xff1a;构建复杂对象的专家 引言 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;用于创建一个复杂的对象&#xff0c;同时允许用户只通过指定复杂对象的类型和内容就能构建它们&#xff0c;它将对象的构建和表示分离&am…

【机器学习】12.十大算法之一支持向量机(SVM - Support Vector Machine)算法原理讲解

【机器学习】12.十大算法之一支持向量机&#xff08;SVM - Support Vector Machine&#xff09;算法原理讲解 一摘要二个人简介三基本概念四支持向量与超平面4.1 超平面&#xff08;Hyperplane&#xff09;4.2 支持向量&#xff08;Support Vectors&#xff09;4.3 核技巧&…

【Django+Vue3 线上教育平台项目实战】构建课程详情页与集成视频播放功能

文章目录 前言一、课程列表页面a.后端代码b.前端代码 二、课程详情页面a. 视频播放功能的集成1.获取上传视频的链接地址2.集成在前端页面中1>使用vue-alipayer视频播放组件2>使用video标签 b. 页面主要内容展示1.后端代码1>分析表2>核心逻辑 2.前端代码3.效果图 前…