9.28总结

9.28总结

知识回顾

# 1. 封装一个函数:获取指定数据的阶乘 【没有指定数据的话默认求10的阶乘】   默认参数
# 阶乘 比如5!=5*4*3*2*1
# 未知数据  有1个
# 是否需要返回结果
def factorial(num=10):
    result = 1
    for i in range(num, 0, -1):
        result *= i
    return result

print(factorial(7))
print(factorial())
# 2. 封装一个函数:求多个数据中的偶数之和  [可变参数]
def get_sum(*nums):
    total = 0
    for ele in nums:
        if ele % 2 == 0:
            total += ele
    return total


print(get_sum(18, 27, 35, 46))
# 3. 设计一个函数:功能是进行自我介绍, 但是不同的人自我介绍的信息不同  信息传递时需要指明信息标题与信息值
# 比如 姓名=小红
def introduce(**infos):
    print(infos)  # 字典类型容器数据  存储的键值对数据  信息绑定的数据  标题和值绑定在一起

introduce(姓名='小明', 年龄=18, 毕业院校='加里敦大学')  # 关键字参数传值
introduce(姓名='小红', 出生年份=2000, 毕业院校='加里敦大学', 专业='挖煤')

# 命名关键字参数   定义函数的时候 参数是定义在*号后面 传值的时候必须使用关键字形式传值
def register(*, username, password):
    print(username, password)

register(username='admin', password='123456')
2.7.3 递归算法

算法:前辈们总结出来的解决某种问题的方法

递归:函数自己内部调用自己的结构称为递归,递归是循环的另外一种表达形式

能形成递归代码的问题都是有规律的,可以找到规律,把规律映射成函数

斐波拉契数列:求第N个月的兔子的对数

公式:
F(1) = 1
F(2) = 1
F(n) = F(n-1) + F(n-2) (n>=3)

F可以映射成函数名,小括号中的n映射成形参

注意:

  1. 写递归的时候一定要有已知项【代表了递归的出口】,没有这个已知项相当于形成了死循环
  2. 递归的层次不能太深 【递归就是在重复的调用自己 就是一个循环 可能会造成程序卡顿 或者 程序崩溃】
# 求第N个月兔子的对数
"""
F(1) = 1
F(2) = 1
F(n) = F(n-1) + F(n-2) (n>=3)
"""
def F(n):
    if n == 1 or n == 2:
        return 1
    else:
        return F(n-1) + F(n-2)  # F(2) + F(1)  # 1 + 1

# 调用函数
print(F(1))
print(F(2))
print(F(3))
"""
求1-N的累加和
F(1) = 1
F(2) = 1 + 2 = F(1) + 2
F(3) = 1 + 2 + 3 = F(2) + 3
....
F(n) = F(n-1) + n   n>=2
"""
def get_sum(n):
    if n == 1:
        return 1
    else:
        return get_sum(n - 1) + n


print(get_sum(10))
"""
数字  不要使用字符串
传递数据的位数  呈现指定的数据
位数为1位数  呈现的2
为2位数  呈现的22
为3位数  呈现的222

第一种
F(1) = 2
F(2) = 22 = F(1) * 10 + 2
F(3) = 222 = F(2) * 10 + 2
....
F(n) = F(n-1) * 10 + 2

第二种
F(1) = 2
F(2) = 22 = 2*10 + F(1) = 2*10**(2-1) + F(1)
F(3) = 222 = 2*100 + F(2) = 2*10**(3-1) + F(2)
F(4) = 2222 = 2*1000 + F(3) = 2*10**(4-1) + F(3)
....
F(n) = 2 * 10 **(n-1) + F(n-1)

"""
def get_num(n):
    if n == 1:
        return 2
    else:
        return get_num(n-1) * 10 + 2

def get_num1(n):
    if n == 1:
        return 2
    else:
        return 2 * 10 ** (n-1) + get_num1(n-1)
# 面试题:
"""
吃豆子,一次只能吃1颗或者2颗,但是不能连续两次吃2颗, 问N颗豆子的吃完的方法有多少种
1颗  1种 
2颗  2种  
3颗  3种  1颗的吃  21  12
4颗  4种  1111   112   121  211
5颗  6种   11111  1112  1121  1211  2111  212
6颗  9种   111111  11112  11121  11211  12111  21111
           1212   2121  2112
7颗  13种  1111111  111112  111121  111211  112111 121111  211111
           11212
           12112  12121
           21112  21121  21211  
F(n) = F(n-1) + F(n-3)  n>=4
    已知项是3个值
"""
def eat_num(n):
    if n <= 3:
        return n
    else:
        return eat_num(n-1) + eat_num(n-3)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.7.4 函数嵌套
全局变量与局部变量

作用域:限定标识符可用性的使用的范围,就称为作用域

在一般的变成语言中代码块一般都是单独的作用域,比如分支结构/循环结构/函数,但是在Python中只有函数有单独的作用域,这个作用域限定了在函数定义的变量只能在函数中使用,这个变量称为局部变量【换句话说这个变量只能应用于函数体内,出了函数没有意义】

注意:形式参数也是局部变量,随着函数的定义才出现的

def add(a, b):
    return a + b

print(add(a=18, b=22))

# 在函数外部 打印a和b的值
# print(a, b)  # NameError: name 'a' is not defined  # a是未定义的
# 出了函数就没意义了

全局变量:定义的这个变量可以在任意位置使用,称为全局变量

name = '小红'    # 函数外

def show_name():
    print(name)

# 调用函数
show_name()

# 定义一个函数:修改名称
def update_name():
    name = '小丽'  # 如果没有这个标记,解释器会认为这个变量是在函数内部重新定义的,与全局没有关系
update_name()
print(name)  # 小红

# 修改全局的名称
def update_name1():
    global name   # 告诉解释器 将使用的这个name是全局变量
    name = '小丽'

update_name1()
print(name)  # 小丽

介绍一个修饰符:global

使用场景:要在函数中修改全局变量的值时,需要在函数中先对变量进行标记[将其标记为全局变量], 如果没有这个标记,解释器会认为这个变量是在函数内部重新定义的,与全局没有关系

内存结构

内存也是分为不同的区域的,不同的区域存储的数据是不一样的,数据的生命周期也是不一样的,区域有:

  1. 栈区

    调用的函数存储与栈区,栈区有一个存储特点:先进后出【类似于向上开口的容器】,函数运行完会被立即释放

  2. 堆区

  3. 常量池

    常量池中存储的是数值类型以及字符串类型的数据

    特点:获取数据时检查数据是否在常量池中存在,如果存在的话直接根据地址获取数据,如果不存在,先分配空间添加数据,再把数据的地址赋值给变量

    生命周期:当程序结束的时候才会释放

  4. 静态池

    存储全局变量【直接在py文件中定义的变量称为全局变量】

    生命周期:当程序结束的时候才会释放

  5. 方法区

    定义的方法或者类会存储于方法区中

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

函数嵌套【了解】

在一个函数中定义了另外一个函数,这种格式称为函数嵌套

了解的内容是**闭包/装饰器

闭包: 在函数嵌套 内层函数应用了外层函数的变量,这种结构就称为闭包
# 函数嵌套格式
def outer():
    print('外层函数')
    def inner():
        print('内部函数')
        
# 了解的是如何调用到内层函数
outer()  # 调用外层函数
# 能直接写inner()??  为什么不能??   函数有自己作用域 在函数中内部定义的内容只能在函数内部使用 外部无法直接拿到
# inner()  # 不能这样调用内层函数

# 不能直接调用 只能间接调用
"""
格式1: 在外层函数中 定义完即运行
"""
def outer1():
    print('外层函数1')
    def inner1():
        print('内部函数1')
    # 调用
    inner1()

outer1()

"""
格式2: 不让其直接运行  向手动调用
 把内部函数当做数据值返回
 注意:返回的时候不要加()
    因为 函数名() 代表的是调用函数  运行函数内部机制  此时返回不是函数本身 而是函数的运行结果
"""
def outer2():
    print('外层函数1')
    def inner2():
        print('内部函数1')
    # 返回
    return inner2

res3 = outer2()
print(res3)  # <function outer2.<locals>.inner2 at 0x000002217D7814C0>
res3()
nonlocal
"""
在内部函数中修改外部函数中的局部变量时  会使用nonlocal
"""

def outer4():
    num = 10
    def inner4():
        nonlocal num
        num = 100
        print('内层函数:', num)
    inner4()
    print('外层函数的num值', num)

outer4()

装饰器

# 装饰器:特殊的闭包
"""
除了在内层函数中使用了外层函数的变量外,外层函数的返回值是内层函数  
"""
"""
装饰器使用来装饰函数或者类的,目的是在执行功能的时候 除了执行功能本身之外 还增加了额外的功能
"""
# 求和的功能
def get_sum(a, b):
    if type(a) != int or type(b) != int:
        raise TypeError('excepted int')
    return a + b

# 求差的功能
def get_sub(a, b):
    if type(a) != int or type(b) != int:
        raise TypeError('excepted int')
    return a - b

"""
上面代码中 判断数据是否是整数类型的操作是被重复书写的
为了简化代码:会把重复的功能封装成函数
"""
def check_type(a, b):
    if type(a) != int or type(b) != int:
        raise TypeError('excepted int')
    return True


def get_mul(a, b):
    result = check_type(a, b)
    if result:
        return a * b


print(get_mul(12, 3.4))


# 一开始把各种运算功能全部写完了
def div(a, b):
    return a / b

def mod(a, b):
    return a % b

# 产品经理:函数执行的时候 验证数据是否是整数类型的  【有没有不修改写好的功能 直接增加类型判断的操作???】
# 装饰器 相对于上面来说会更加简洁一些  不用在动写好的功能了
# 将写好的装饰器使用语法糖的形式 给需要增加类型判断的函数 装饰一下
# @语法糖

')
return True

def get_mul(a, b):
result = check_type(a, b)
if result:
return a * b

print(get_mul(12, 3.4))

一开始把各种运算功能全部写完了

def div(a, b):
return a / b

def mod(a, b):
return a % b

产品经理:函数执行的时候 验证数据是否是整数类型的 【有没有不修改写好的功能 直接增加类型判断的操作???】

装饰器 相对于上面来说会更加简洁一些 不用在动写好的功能了

将写好的装饰器使用语法糖的形式 给需要增加类型判断的函数 装饰一下

@语法糖


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值