函数嵌套调用

def a():
    print('AAAAAAA')


def b():
    # 调用函数a
    a()
    print('BBBBBBB')


def c():
    b()
    print('CCCCCCC')


c()

例子

# 定义函数:随机数产生
# 自动格式化Ctrl+Alt+L
import random


def generate_random():
    for i in range(20):
        ran = random.randint(1, 20)
        print(ran)


print(generate_random)
# <function generate_random at 0x000002755D17E040>
#  函数名      函数           在  内存地址


# 调用:函数名() 找到函数并执行函数体
print('------1------')
generate_random()
print('------2------')
generate_random()
# 函数:带参数的
import random


def generate_random(ran, ranmin, ranmax):  # 形参,用来占位的参数,这里是ran,ranmin,ranmax
    for i in range(ran):
        ran1 = random.randint(ranmin, ranmax)
        print(ran1)


num = int(input('请输入要产生的随机数个数:'))
num2 = int(input('请输入要产生的随机数范围最小值:'))
num3 = int(input('请输入要产生的随机数范围最大值:'))
generate_random(num, num2, num3)  # 实参 实际参数,具体的值


# 求加法的函数

def add(a, b):
    print('加起来等于', a + b)


a = int(input('输入第一个数:'))
b = int(input('输入第二个数:'))
add(a, b)
"""
定义一个登录的函数,参数是:username,password
函数体:
判断参数传过来的是username,password是否正确,如果正确则登录成功,否则打印失败

"""


# 函数的定义
def login(username, password):
    uname = 'admin123'
    pwd = '112233'
    for i in range(3):
        if username == uname and password == pwd:
            print('输入正确')
            break
        else:
            print('输入错误')
            username = str(input('输入用户名:'))
            password = str(input('输入密码:'))
    else:
        print('账户锁定!')


username = str(input('输入用户名:'))
password = str(input('输入密码:'))
login(username, password)
# 找出列表的最大值
# 自己封装一个求最大值函数
def max(iterable):
    max = iterable[0]
    for i in iterable:
        if i > max:
            max = i
    print('最大值是:', max)


# 调用:测试是否能找出最大值
list1 = [4, 1, 4, 3, 8, 9]
max(list1)

tuple1 = (3, 6, 1, 0, 5)
max(tuple1)

# sort min reverse
print(type(tuple1))  # 查看是什么类型

# 判断是不是什么类型:isinstance
print(isinstance(2, int))  # 返回值是False,True
print(isinstance(tuple1, tuple))
# 可变参数

# def add(*args):
#     print(args)
#
#
# add(1)

# 定义方式
# def add(*args):
#     # *args的用法:当传入的参数个数未知,且不需要知道参数名称时。
#     # print(args)
#     sum = 0
#     if len(args) > 0:
#         for i in args:
#             sum += i
#         print('累加的和是sum:', sum)
#     else:
#         print('没有元素可计算,sum:', sum)
#
#
# add()
# add(1)
# add(1, 2)
# add(1, 2, 3, 4)

# xxx计算出来的累加和是:xxx

def add(name, age, *args):
    # **args的用法:当传入的参数个数未知,但需要知道参数的名称时(立马想到了字典,即键值对)
    print(args, name)
    sum = 0
    if len(args) > 0:
        for i in args:
            sum += i
        print('{}累加的和:sum:{}'.format(name, sum))
    else:
        print('没有元素可计算:sum:', sum)


# 调用
add('菲菲', 4, 6, 8)
# 注意:可变参数必须放在后面:name,*args
add('我', 10)
# name,age, *args='我',10
# # 可变参数 + 关键字参数
# # 关键字参数:key=value 键值对
#
# def add(a, b=10):  # 关键字参数
#     result = a + b
#     print(result)
#
#
# # 调用
# add(5)
# add(4, 7)  # a=4,b=7   覆盖默认值
#
#
# def add1(a, b=10, c=4):
#     result = a + b + c
#     print(result)
#
#
# add1(1)
# add1(1, 5)  # 给b赋值
# add1(1, c=6)  # 直接将6赋值给c
#
# # 函数:打印每位同学姓名和年龄
#
studens = {
    '001': ('蔡徐坤', 20),
    '002': ('王源', 18),
    '003': ('王俊凯', 21),
    '004': ('易烊千玺', 19)
}


def print_boy(name, **persons):
    print('{}喜欢吃肉肉'.format(name))
    if isinstance(persons, dict):  # 判断是不是什么类型:isinstance,这里判断是不是person是不是字典类型
        values = persons.values()  # 如果是字典,那么使用values接受字典里面的键值对
        # print(values)             # 输出字典
        for name, age in values:  # 使用name和age接受values中的键值对
            print('{}的年龄是{}'.format(name, age))  # 循环输出字典中的元素


print_boy('健健', **studens)
#
#
# def func(**key):
#     print(key)
#
#
# func(a=1, b=1, c=1)
# dict1 = {'001': 'python', '002': 'java', '004': 'c++'}
#
#
# func(**dict1)
"""
使用函数的时候:
def aa(*kwargs):
    pass
"""


def aa(**kwargs):  # 只要在定义函数的时候加入**就是装包
    print(kwargs)


aa(a=1, b='hello', c='tom')  # 装包成字典
# 如果在开发的时候,已知一个字典
dict1 = {'a': 1, 'b': 'hello', 'c': 'tom'}
aa(**dict1)  # 只要在调用函数的时候加入**就是拆包


def bb(a, b, *c, **d):
    print(a, b, c, d)


bb(1, 2)  # 打印两个参数 1 2 一个元组,一个字典
bb(1, 2, 3, 4)  # 打印 ,1 2 (3,4) {}
bb(1, 2, x=100, y=200)  # 1 2 () {'x':100,'y':200}
bb(1, 2, 3, x=100)  # 1 2 (3,) {'x':100}
bb(1, 2, x=100)
def func(a, *args):
    print('{}{}'.format(a, args))


func(2, [1, 23, 4], 'fad')


def func2(a, b=10, c=3, **kwargs):
    print(a, b, c, kwargs)


func2(1)  # 1 10 3 {}  给默认值所以可传入一个参数
func2(2, b=11)  # 2 11 3 {}
func2(3, c=5, b=7, x=1, y=2)  # 3 7 5 {'x': 1, 'y': 2},传值的时候可以打乱位置


def func3(a, *args, **kwargs):
    print(a, args, kwargs)


t = (1, 2, 3, 4)
func3(1, t)  # 1 ((1, 2, 3, 4),) {}

l = [2, 5, 8]
func3(1, l, c=9, b=6)  # 1 ([2, 5, 8],) {'c': 9, 'b': 6}

dict1 = {'1': 'a', '2': 'b', '3': 'c'}
func3(1, *l, **dict1)  # 1 (2, 5, 8) {'1': 'a', '2': 'b', '3': 'c'}        # *拆列表 **拆字典


def func1(name, *args):
    if len(args) > 0:
        for i in args:  # 这里args是元组
            print('{}学过了{}'.format(name, i))
    else:
        print('没有学过任何语言')


courses = ['html', 'mysql', 'c++', 'python']
# 调用函数
func1('健健', *courses)  # *拆列表(拆包)
'''
无参数函数:
    def func():
        pass
    func() ---调用
    
    有参数函数
1.普通参数
    def func(name,age):
        pass
    func('aa',19) --->形参与实参的个数要一致

2.可变参数:
    A.
        def func(*args):
            pass
        func() ----> 函数调用时,实参的个数可以没有,也可以多个,*不能是关键字参数
        func(4) 
        func(5,'h')

    B.
        def func(**kwargs):
            pass
        func(a=1,b=2)----> 函数调用时,实参的个数可以没有,也可以多个,**必须是关键字参数
    
    C.
        def func(*args,**kwargs):
            pass
        list1 = [1,2,3,4,5]
        dict1 = {'1':'a','2':'b','3':'c'}
        func(*list1,**dict1)    拆包func(1,2,3,4,5,'1':'a','2':'b','3':'c')
    
    D.混用
        def func(name,*args,*8kwargs):
            pass
        func('tom') ---->必须赋值
3.默认值
    def func(name,age=18):
        pass
    func('tom') ----> tom 18
    func('tom',age = 20) ---->关键字赋值
        
'''
# 返回值:将函数中运算的结果通过return关键字‘扔’出来
# 如果使用print这个值就不会出来只会在def内部打印,外面是接受不到的

# def add(a, b):  # 加载
#     result = a + b
#     # print(result)
#     return '这都不会', result
#
#
# # 调用函数
# # add(2, 4) 这里只能打印函数中的print内容不会接收return
# x, y = add(2, 4)
# print(x, y)

'''
return 返回值
1.return后面可以是一个参数 接收的时候x=add(1,2)

2.return后面也可以是多个参数,如果是多个参数则底层会将多个参数先放在一个元组中,
    将元组作为整体返回 x=add(1,2) x--> (1,2,3)
3.接收的时候也可以是多个:return 'hello','world' x,y = ('hello','world') --->x = 'hello' y = 'world'

'''
'''
加入购物车
判断用户是否登录,如果登录,成功加入购物车,否则提示请登录之后添加
成功 True     不成功 False
def add_shoppingcart(goodsName):
    pass
def login(username,password):
    pass

调用
'''
# isLogin = False
#
#
# def add_shoppingcart(goodsName):
#     if isLogin and goodsName:
#         print('成功将{}加入到购物车!!!'.format(goodsName))
#     else:
#         print('用户没有登录!或者没有添加如何商品请登录之后添加')
#     return isLogin
#
#
# def login(username, password):
#     if username == 'zhao' and password == '123456':
#         return True
#     else:
#         print('登录失败用户名或者密码错误')
#         return False
#
#
# # 调用函数
# while True:
#     username = input('输入用户名:')
#     password = input('输入密码:')
#     isLogin = login(username, password)
#     y = add_shoppingcart('榴莲')
#     if isLogin:
#         break
isLogin = False


def add_shoppingcart(goodsName):
    global isLogin
    if isLogin:
        if goodsName:
            print('成功将{}加入到购物车!!!'.format(goodsName))
        else:
            print('没有选中任何商品')
    else:
        answer = input('没有登录!是否登录(yes/no)')
        if answer == 'yes':
            # 登录
            username = input('输入用户名:')
            password = input('输入密码:')
            # 调用login
            isLogin = login(username, password)  # 在一个函数中调用另外一个函数 将login函数中return的值赋值给islogin
            print(isLogin)
            return isLogin
        else:
            print('很遗憾,不能添加如何商品')

    return isLogin


def login(username, password):
    if username == 'zhao' and password == '123456':
        return True
    else:
        return False


# 调用函数
username = input("请输入用户名:")
password = input("请输入密码:")
# shoping = input("请输入你要买的商品:")
# add_shoppingcart(shoping)
isLogin = login(username, password)
add_shoppingcart("isLogin")
# # 函数综合应用
# '''
#     用户登录
#     输入密码
#     输入验证码 --->封装函数
# '''
import random


#
# 我写的
# def yzm():
#     # 生成验证码
#     code = ''
#     ymzs = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0987654321'
#     for i in range(4):
#         a = random.randint(0, len(ymzs) - 1)
#         code += ymzs[a]
#     print('验证码是', code)
#     return code
#
#
# def yz(codes):
#     # 判断验证码
#     if codes == x:
#         return '验证码正确'
#         # print('验证码正确')
#     else:
#         return '验证码错误'
#         # print('验证码错误')
#
#
# def login(username, password, codes, x):
#     if username == '1' and password == '1' and codes == x.lower():
#         print('登录成功')
#     if codes != x.lower():
#         print('登录失败,验证码错误')
#     else:
#         print('登录失败,密码或用户名错误')
#
#
# x = yzm()
# username = input('请输入用户名:')
# password = input('请输入密码:')
# codes = input('请输入验证码')
# cdoes = codes.lower()
# login(username, password, codes, x)
# if codes == x.lower():
#     print('验证码正确')
# else:
#     print('登录失败,验证码错误')


# 定义一个生成验证码函数   老师写的
def generate_chekcode(n):
    code = ''
    for i in range(n):
        str1 = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0987654321'
        a = random.randint(0, len(str1) - 1)
        code += str1[a]
    return code


# 定义登录函数
def login():
    username = input('输入用户名:')
    password = input('输入密码:')
    # 得到一个验证码
    code = generate_chekcode(5)
    print('验证码是:', code)
    code1 = input('输入验证码:')
    # 验证
    if code1.lower() == code.lower():
        print('验证码正确')
        if username == 'admin' and password == 'admin':
            print('登录成功')
        else:
            print('登录失败,用户名或密码有误!!!')
    else:
        print('验证码不正确')


login()
# 局部和全局
# 如果修改的变量是全局变量时,在函数中修改时需要加global
# 如果修改的变量是可变的时候,不需要在函数中加global
name = '月月'
list1 = [1, 2, 3, 4]


def func():
    name = '蕊蕊'
    print(name)
    print(list1)


def func1():
    global name
    print(name)
    name += '真漂亮'
    list1.append(8)
    print(list1)


def func2():  # 可以使用不同的变量名字来使用global,不要和global起一样的名字
    name1 = 'lucy'
    name1 += '嘻嘻'
    global name
    print(name)


func1()
func()
func2()
# global    变量的范围
# 局部变量    全局变量
# 声明在函数外层的是全局的,所有函数都可以访问。(不能修改)
name = '丽丽'


def func():
    # 函数内部声明的变量,局部变量,局部变量仅限于函数内部使用
    s = 'abcd'
    s += 'X'
    print(s, name)


# print(s) 报错

def func1():
    global name  # 声明我使用的是全局变量,声明之后就可以修改全局变量,
    # print(s)
    print('没有修改的name', name)  # 报错:函数内部的变量可以随便修改赋值,但是全局变量就不能随便修改
    name += '会吃shit'
    print('修改后的name', name)


def func2():
    name = '小丽丽'
    name += '弹吉他的小美女'
    print(name)


func2()
func1()
# 内部函数
'''
特点:
1、可以访问外部函数的变量
2、内部函数可以修改外部函数的可变类型的变量比如:list1
3、内部函数修改全局的不可变变量时,需要在内部函数声明global 变量名
   内部函数修改外部函数的不可变的变量时,需要在内部函数中声明:nonlocal 变量名
4、
'''


def func():
    # 声明变量
    n = 100  # 内部函数
    list1 = [1, 2, 3, 4]  # 局部变量

    # 声明内部函数
    def inner_func():
        nonlocal n  # 加nonlocal可以修改内部函数,nonlocal 关键字用于在嵌套函数内部使用变量,其中变量不应属于内部函数。
        # 对list1里面的元素进行加5操作
        for index, i in enumerate(list1):  # 枚举将list1中的每个元素取出来
            # index是元素下表,i是list1中的元素
            list1[index] = i + n
        list1.sort()
        n += 101

    # 调用一下内部函数才会执行
    inner_func()
    print(list1)
    print(n)


# 调用func
func()
a = 100  # 全局变量


def func():
    # 声明变量
    b = 99

    # 声明函数
    def inner_func():
        nonlocal b  # 修改局部变量
        global a  # 修改全局变量
        c = 88
        # 尝试修改
        c += 12
        b += 1
        # 尝试打印
        a += 10
        print(a, b, c)

    # 调用内部函数
    inner_func()
    # 使用locals()内置函数进行查看,可以看到当前函数中声明的内容有哪些
    # locals()是一个字典,key:value
    print(locals())
    print(globals())


# 调用函数
func()
# 闭包
# 函数中 提出的概念,
'''
条件:
1.外部函数中定义了内部函数
2.外部函数是有返回值
3.返回值的是:内部函数
4.内部函数引用了外部函数的变量
格式:
def 外部函数():
    ...
    def 内部函数():
        ...
    return 内部函数

'''


def func():
    a = 100

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

    print(locals())
    return inner_func  # 不能加括号,如果加括号表示调用,不加括号才是扔出去


x = func()
print(x)
# x就是内部函数,x()就表示调用函数
x()
# 闭包
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()  # 当你调用func(6,9)---->a=6,b=9---->inner_func()内部函数---->返回内部函数
# (此时返回的内部函数已经记录此时的a和b的值,所以不会收到a,b改变影响
ifunc1 = func(2, 8)
ifunc1()
# 计数器
def generate_count():
    container = [0]

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

    return add_one


# 内部函数就是一个计数器
counter = generate_count()
counter()  # 第一次访问
counter()  # 第二次访问
counter()  # 第三次访问
'''
闭包有什么缺点呢?
闭包的缺点1,作用域没有你们直观
闭包的缺点2,因为变量是不会被垃圾回收所以有一定的内存占用问题。

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

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

'''


def func():
    a = 100

    def inner_func1():
        b = 90
        s = a + b
        print(s)

    def inner_func2():  # define
        inner_func1()  # 调用inner_func1
        print('------>inner_func2', a)  # 同级可以访问
        return 'hello'

    return inner_func2  # 加括号表示调用,而不是扔出去


# 调用func
f = func()  # 接收return inner_func2
# print(f)            # 输出内存地址才正确<function func.<locals>.inner_func2 at 0x0000026BEBBEED30>
f()  # 显示return inner_func2
ff = f()  # 使用ff接收return ’hello‘,就可以输出hello
print(ff)
# 装饰器
'''
加入购物车,付款,修改收货地址。。。。。
判断用户的登录状态,
'''


def func(number):
    a = 100

    def inner_func():
        nonlocal a, number
        number += 1
        for i in range(number):
            a += 1
        print('修改后的a:', a)

    return inner_func


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

# 装饰器函数作为参数

a = 50
f1 = func(a)  # a是实参
f1()
# # 地址的引用
# a = 10  # 声明整形的变量
# b = a
#
#
# def test():  # 声明函数
#     print('---------------test-------------')
#
#
# t = test  # 将test()函数内存地址赋值给t
# t()
#
#
# def func(f):
#     print(f)  # <function test at 0x000001AB91B0E040>
#     f()  # -----------test-------
#     print('-----------func----------')
#
#
# # 调用
# func(test)
'''
特点:
1.函数A是作为参数出现的(函数B就接收函数A作为参数)
2.要有闭包的特点
'''


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

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

    print('wrapper加载结束')
    return wrapper


# 使用装饰器
@decorate  # 需要在decorate这个函数传入函数
def house():
    print('我是毛胚房。。。。')


'''
1.house被装饰函数,
2.将被装饰函数作为参数传给装饰器decorate
3.执行decorate函数
4.将返回值又赋值给house
'''
print(house)
house()
# def house1():
#     print('刷油漆')
#     print('铺地板')
#
#

# 调用house
# house()
# 登录校验
import time


def decorate(func):
    def wrapper(*args, **kwargs):  # 万能装饰器
        print('正在校验中.....')
        time.sleep(2)  # 休眠里面
        print('校验完毕.....')
        # 调用原函数
        func(*args, **kwargs)

    return wrapper


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


f1(1)  # 此时f1是wrapper


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


f2('丽丽', 20)


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


studens = ['lili', 'gg', 'bao']
f3(studens, clazz='1904')


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


f4()
'''
print
正在校验中.....
校验完毕.....
------f1----- 1
正在校验中.....
校验完毕.....
------f2----- 丽丽 20
正在校验中.....
校验完毕.....
1904班级的学生如下:
lili
gg
bao

'''
# 装饰器
'''
如果装饰器是多层的,谁距离函数u最近就优先使用那个装饰器
'''


def zhuang1(func):
    print('------1 start')

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

    print('------1 end')
    return wrapper


def zhuang2(func):
    print('------2 start')

    def wrapper(*args, **kwargs):
        func()
        print('扣地板')

    print('------2 end')
    return wrapper


@zhuang2
@zhuang1  # 谁近先装谁
def house():
    print('我是毛胚房.....')


house()
'''
------1 start
------1 end
------2 start
------2 end
我是毛胚房.....
刷漆
扣地板
'''
# 装饰器带参数,需要三层函数
'''
带参数的装饰器是三层的
最外层的函数负责接收装饰器参数
里面的内容函数原装饰器的内容
'''


def outer(a):  # 第一层
    def decorate(func):  # 第二层
        def wrapper(*args, **kwargs):  # 第三层
            func(*args, **kwargs)
            print('------>铺地砖{}块'.format(a))

        return wrapper  # 返出来的是第三层

    return decorate  # 返出来的是第二层


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


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


house('2019-6-12')
street()
# 开发:登录验证
import time

isLogin = False  # 默认没有登录


def login():
    username = input('输入用户名:')
    password = input('输入密码:')
    if username == 'admin' and password == 'admin':
        print('登录成功')
        return True
    else:
        print('登录失败,用户名或密码错误')
        login()
        return False


# 定义一个装饰器,进行付款验证
def login_required(func):
    def wrapper(*args, **kwargs):
        global isLogin
        print('-----正在进行付款-----')
        # 验证用户是否登录
        if isLogin:
            func(*args, **kwargs)
        else:
            # 跳转到登录页面
            time.sleep(2)
            print('用户没有登录,请登录之后再付款')
            isLogin = login()

    return wrapper


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


pay(10000)
pay(10000)

'''
-----正在进行付款-----
用户没有登录,请登录之后再付款
输入用户名:admin
输入密码:admin
result True
-----正在进行付款-----
正在付款,付款金额是:10000元
付款中...
付款完成
'''