【十一】Python 内部函数

内部函数

# 内部函数
'''
特点:
1. 可以访问外部函数的变量
2. 内部函数可以修改外部函数的可变类型的变量比如:list1
3. 内部函数修改全局的不可变变量时,需要在内部函数声明global 变量名
   内部函数修改外部函数的不可变的变量时,需要在内部函数中声明: nonlocal 变量名
4. locals() 查看本地变量有哪些,以字典的形式输出
   globals() 查看全局变量有哪些,以字典的形式输出(注意里面会有一些系统的键值对)
'''
def func():
    # 声明变量
    n = 100  # 局部变量
    list1 = [3, 6, 9, 4]  # 局部变量

    # 声明内部函数
    def inner_func():
        nonlocal n
        # 对list1里面的元素进行加5操作
        for index, i in enumerate(list1):
            # 0  3
            list1[index] = i + n

        list1.sort()

        # 修改n变量
        n += 101

    # 调用一下内部的函数
    inner_func()

    print('打印老大n:',n) #打印老大n: 201
    print('打印老二list1:',list1) #打印老二list1: [103, 104, 106, 109]
	
# 调用func
func()

 locals() globals()

a = 100  # 全局变量
print(globals())
#{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000012F0E362F28>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python Script/demo-01.py', '__cached__': None, 'a': 100}

# 定义函数
def func():
    # 声明变量
    b = 99
    # 声明函数
    def inner_func():
        global a
        nonlocal b
        c = 88
        # 尝试修改
        c += 12
        b += 1
        a += 10
        # 尝试打印
        print(a, b, c) #110 100 100

    # 调用内部函数
    inner_func()
    # 使用locals()内置函数进行查看。可以看到在当前函数中声明的内容有哪些
    # locals()是一个字典。key:value
    print(locals()) #{'inner_func': <function func.<locals>.inner_func at 0x0000012F0E838EA0>, 'b': 100}

# 调用函数
func()

闭包

# 闭包
# 在函数中提出的概念,
'''
条件:
1. 外部函数中定义了内部函数
2. 外部函数是有返回值
3. 返回的值是:内部函数名
4. 内部函数引用了外部函数的变量

格式:
def 外部函数():
    ...
    def 内部函数():
        ....
    return 内部函数
'''
def func():
    a = 100

    def inner_func():
        b = 99
        print(a, b)

    print(locals()) #{'inner_func': <function func.<locals>.inner_func at 0x0000013C88BA8EA0>, 'a': 100}

    return inner_func

# print(a)
# inner_func()

x = func()
print(x)  # <function func.<locals>.inner_func at 0x00000000021500D0>
# x就是内部函数,x()就表示调用函数
x() #100 99
# 闭包
def func(a, b):
    c = 10

    def inner_func():
        s = a + b + c
        print('相加之后的结果是:', s)

    return inner_func

# 调用func
ifunc = func(6, 9)  # ifunc就是inner_func   ifunc = inner_func

# 调用返出来的内部函数
ifunc()

闭包的应用

def func(a, b):
    c = 10

    def inner_func():
        s = a + b + c
        print('相加之后的结果是:', s)

    return inner_func


# 调用func
ifunc = func(6, 9)  # ifunc就是inner_func   ifunc = inner_func #<function func.<locals>.inner_func at 0x0000029AB5568EA0>
ifunc1 = func(2, 8) #<function func.<locals>.inner_func at 0x0000029AB5568F28>
ifunc2 = func(1, 9) #<function func.<localsa>.inner_func at 0x0000029AB556F048>

print(ifunc) #相加之后的结果是: 20
print(ifunc1) #相加之后的结果是: 25
print(ifunc2) #相加之后的结果是: 20

ifunc1()
ifunc()
ifunc2()


# 计数器
def generate_count():
    container = [0]

    def add_one():

        container[0] = container[0] + 1  # [2]
        print('当前是第{}次访问'.format(container[0]))

    return add_one


# 内部函数就是一个计数器
counter = generate_count()   # counter = add_one

counter()  # 第一次的访问 #1
counter()  # ....         #2
counter()                 #3
'''

在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,
并且把里面的函数返回,我们把这种情况叫闭包

内部函数对外部函数作用域里变量的引用
内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。


访问外部函数的可变类型局部变量可不加nonlocal
访问外部函数的不可变类型局部变量要加 nonlocal


闭包有什么缺点呢?
闭包的缺点1,作用域没有那么直观
闭包的缺点2,因为变量不会被垃圾回收所以有一定的内存占用问题。

闭包作用:1.可以使用同级的作用域
闭包作用:2.读取其他元素的内部变量
闭包作用:3.延长作用域


闭包总结
1.闭包似优化了变量,原来需要类对象完成的工作,闭包也可以完成.
2.由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存.
3.闭包的好处,使代码变得简洁,便于阅读代码。
4.闭包是理解装饰器的基础
'''
def func():
    a = 100

    def inner_func1():
        b = 90
        s = a + b
        print(s) #<function func.<locals>.inner_func2 at 0x000002A1E7C78F28>

    def inner_func2():   # define
        inner_func1()  # 调用inner_func1
        print('-----------> inner_func2',a) #190

        return 'hello'

    return inner_func2   # 0x0000000001DE0158

# 调用func
f = func()
print(f)  # <function func.<locals>.inner_func2 at 0x000001DDF1588F28>

ff = f()  # inner_fun2()
print(ff) # 

#190
#-----------> inner_func2 100
#hello

装饰器

# 装饰器
'''
 加入购物车,付款,修改收货地址,。。。
 判断用户的登录状态

'''
#返回函数

def func(number):
    a = 100

    def inner_func():
        nonlocal a
        nonlocal number
        number += 1

        for i in range(number):
            a += 1
        print('修改后的a:', a) #修改后的a: 106

    return inner_func

# 调用func
f = func(5)
f()

# 函数作为参数
a = 50
f1 = func(a)  # a是一个实参
print(f1)     #<function func.<locals>.inner_func at 0x000001DFD1038F28>
# 地址引用
a = 10  # 声明整型变量
b = a

def test():  # 声明函数
    print('------test-------')

# t = test
# test() #------test-------
# t() ------test-------

# def func(f):  # f=test
#     print(f)  # <function test at 0x0000000001D01E18>
#     f()  # -------test---------
#     print('------------>func')
#
#
# # 调用
# func(test)

'''
特点:
1. 函数A是作为参数出现的(函数B就接收函数A作为参数)
2. 要有闭包的特点
'''

# 定义一个装饰器
def decorate(func):
    a = 100
    print('wrapper外层打印测试')

    def wrapper():
        func()
        print('--------->刷漆')
        print('--------->铺地板', a)
        print('--------->装门')

    print('wrapper加载完成......')
    return wrapper


# 使用装饰器
@decorate
def house():
    print('我是毛坯房....')

'''
默认执行的:
1. house被装饰函数,
2. 将被装饰函数作为参数传给装饰器decorate
3. 执行decorate函数
4. 将返回值又赋值给house
'''
print(house) ##<function decorate.<locals>.wrapper at 0x00000207B1B10048>
house() 

#wrapper外层打印测试
#wrapper加载完成......
#<function decorate.<locals>.wrapper at 0x00000207B1B10048>
#我是毛坯房....
#--------->刷漆
#--------->铺地板 100
#--------->装门

# def house1():
#     house()
#     print('刷漆')
#     print('铺地板')


# 调用函数house
# house()

装饰器参数(万能装饰器)

# 登录校验
import time


def decorate(func):
    def wrapper(*args, **kwargs):  # ()  {'clazz':'1904'}
        print('正在校验中....')
        time.sleep(2)
        print('校验完毕.....')
        # 调用原函数  args --->()
        func(*args, **kwargs)  # f1  f2  f3...

    return wrapper


@decorate
def f1(n):
    print('-------f1-------', n)

f1(5)  # 此时的f1是wrapper,

@decorate
def f2(name, age):
    print('-------f2-------', name, age)

f2('lily', 20)


#
#
@decorate
def f3(students, clazz='1905'):
    print('{}班级的学生如下:'.format(clazz))
    for stu in students:
        print(stu)


students = ['lily', 'tom', 'lucy']
f3(students, clazz='1904')



@decorate
def f4():
    print('------------>f4')

f4()

装饰器离最近优先执行

'''
如果装饰器是多层的,谁距离函数最近就优先使用哪个装饰器
'''
# 装饰器
def zhuang1(func):
    print('------->1 start')

    def wrapper(*args, **kwargs):
        func()
        print('刷漆')

    print('------->1 end')

    return wrapper

def zhuang2(func):# func=house
    print('------->2 start')

    def wrapper(*args, **kwargs):
        func()
        print('铺地板,装门.....')

    print('------->2 end')

    return wrapper


@zhuang2
@zhuang1
def house():  # house = wrapper
    print('我是毛坯房.....')


house()
------->1 start
------->1 end
------->2 start
------->2 end
我是毛坯房.....
刷漆
铺地板,装门.....

 带参装饰器

# 装饰器带参数
'''
带参数的装饰器是三层的
最外层的函数负责接收装饰器参数
里面的内容还是原装饰器的内容
'''
def outer(a):  # 第一层: 负责接收装饰器的参数
    print('------------1 start')

    def decorate(func):  # 第二层 : 负责接收函数的
        print('------------2 start')

        def wrapper(*args, **kwargs):  # 第三层   负责接收函数的参数
            func(*args)
            print("---->铺地砖{}块".format(a))

        print('------------2 end')
        return wrapper  # 返出来的是:第三层

    print('------------1 end')
    return decorate  # 返出来的是:第二层


@outer(10)
def house(time):
    print('我{}日期拿到房子的钥匙,是毛坯房....'.format(time))


# @outer(100)
# def street():
#     print('新修街道名字是:黑泉路')


house('2019-6-12')

# street()


# ------------1 start
# ------------1 end
# ------------2 start
# ------------2 end
# 我2019-6-12日期拿到房子的钥匙,是毛坯房....
# ---->铺地砖10块

综合装饰器示例

import time

islogin = False

#定义一个登录login方法
def login():
    username = input('输入用户名:')
    password = input('输入密码:')
    if username == 'xks' and password == '11111111':
        return True
    else:
        return False

#定义一个装饰器 进行付款验证
def login_required(func):
    def wrapper(*args,**kwargs):
        #修改全局的变量需要进行定义global
        global islogin
        print('付款准备阶段... ... ... ...')
    #    验证用户是否登录
        if islogin:
            func(*args,**kwargs)
        else:
            #跳转到登录页面
            print('用户未登录,无法付款... ... ...')
            islogin = login()
            print('islogin:',islogin)

    return wrapper

@login_required
def pay(money):
    print('正在付款,付款金额是:{}元'.format(money))
    print('付款中')
    time.sleep(2)
    print('付款完成')

pay(10000)
pay(20000)

# 付款准备阶段... ... ... ...
# 用户未登录,无法付款... ... ...
# 输入用户名:xks
# 输入密码:11111111
# islogin: True
# 付款准备阶段... ... ... ...
# 正在付款,付款金额是:20000元
# 付款中
# 付款完成

 

posted @ 2023-09-27 10:09  しみずよしだ  阅读(60)  评论(0)    收藏  举报