1.函数的命名规则:

(1)字母数字下划线,首字母不能为数字;

(2)严格区分大小写,且不能使用关键字;

(3)函数命名有意义,且不能使用中文;

2.驼峰命名法:

(1)大驼峰命名法:每个单词的首字符大写(一般在类中起名用这样的方式,首推)

  mycar=>My_Car    busstop=>Bus_Stop

(2)小驼峰命名法:除第一个单词首字母不需大写,剩下首字母都大写(函数的命名)

  mycar=>myCar   myhouse=>myHouse

首推)

3.九九乘法表:

#九九乘法表
for i in range(1,10):
    for j in range(1,i+1):
        print("%d*%d=%2d"%(i,j,i*j),end=" ")
    print()
#九九乘法表倒背
for i in range(9,0,-1):
    for j in range(1,i+1):
        print("%d*%d=%2d"%(i,j,i*j),end=" ")
    print()
4.函数的定义处和调用处:
#函数的定义处
def cheng_fa_biao_99():
    for i in range(9,0,-1):
        for j in range(1,i+1):
            print("%d*%d=%2d"%(i,j,i*j),end=" ")
        print()
#函数的调用处
cheng_fa_biao_99()
5.函数的参数
(1)形参:形式参数(在函数的定义处)
包含:普通(位置)参数,默认参数,普通收集参数,命名关键字参数,关键字收集参数
(2)实参:实际参数(在函数的调用处)
注:形参和实参要一一对应
举例如下:
#(1)普通形参
def small_start(hang,lie):
    i=0
    while i<hang:
        j=0
        while j<lie:
            print("*",end="")
            j+=1
        print()
        i+=1
#函数的调用处,普通实参
small_start(3,5)

#(2)默认参数,在定义处给与默认值
"""
    如果给与实参,那么就使用实际参数
    如果没有给实参,就使用参数的默认值
"""
def small_start(hang=10,lie=10):
    i=0
    while i<hang:
        j=0
        while j<lie:
            print("*",end="")
            j+=1
        print()
        i+=1
small_start()
small_start(4,9)

#(3)普通形参+默认形参
""""默认形参必须在形参后面,语法上要求"""
def small_start(hang,lie=10):
    i=0
    while i<hang:
        j=0
        while j<lie:
            print("*",end="")
            j+=1
        print()
        i+=1
#函数的调用处
small_start(3)
small_start(4,8)
#(4)关键字形参
"""如果使用关键字参数进行函数调用,实参的顺序无所谓"""
"""如果定义时是普通形参,调用时是关键字实参,那么这个参数后面的所有调用方式都需要关键字实参进行调用"""
def small_start(hang,lie=10):
    i=0
    while i<hang:
        j=0
        while j<lie:
            print("*",end="")
            j+=1
        print()
        i+=1
#函数的调用处,关键字参数,hang,lie
small_start(hang=10,lie=9)
(5)收集参数
"""
收集参数:
(1)普通收集参数:*在函数的定义处
    专门用来收集那些多余的没人要得普通参数,形成一个元组
    语法:def func(*args) =>arguments
def func(*args):
    print(args)   =>返回的书记类型是元组
"""
def func(a,b,c,*args):
    print(a,b,c)
    print(args)
func(1,2,3,4,5,6,7,8,90,9,9,9,9)

#计算任意数的累加和
def mysun(*args):
    totle=0
    for i in args:
        totle+=i
    print(totle)
mysun(11,23,45,56,1,2)
"""
收集参数
    (2)关键字收集参数  **在函数的定义处
    专门用来收集那些多余没人要的关键字实参,形成一个字典
    语法:def func(*kwargs):kwargs=>keyword arguments
def func(**kwargs):
    print(kwargs)   =>返回的数据类型是字典
"""
def func(a=1,b=2,**kwargs):
    print(a,b)
    print("------")
    print(kwargs)
#方法一
func(99,b=99,c=4,d=90,f=78)
#方法二
func(b=99,a=111,c=4,d=90,f=78)
print("-----------")
#拼接任意字符串
dictvar={"monitor"}
def func(**kwargs):
    str1=""
    str2=""
    dictvar={"monitor":"班长","classflower":"班花"}
    for k,v in kwargs.items():
        # print(k,v)
        if k in dictvar:
            str1 += dictvar[k]+":"+v+"\n"
        else:
            str2+=v+" "
    print(str1)
    print("吃瓜群众:",str2)
        # print(str1)
    # print(kwargs)
func(monitor="素则会",classflower="郭一萌",eatgua1="黄花",eatgua2="李存海")
(6)命名关键字参数
"""
(1)def func(a,b,*,参数1,参数2....)在*后面定义的参数就是命名关键字参数
(2)def func(*args,参数,**kwargs)夹在普通收集参数和关键字收集参数之间的命名关键字参数
如果命名关键字参数,必须使用关键字实参来进行调用赋值
"""
#定义方法1
def func(a,b,*,c,d):
    print(a,b)
    print(c,d)
#func(1,2,3,4) 报错代码
func(1,2,c=3,d=4)
#定义方法2
def func(*args,c,**kwargs):
    print(args)
    print(c)
    print(kwargs)
func(1,2,3,4,a=1,b=2,c=3)

#定义方法3
def func(a,b,*,c=3):
    print(a,b)
    print(c)
#2种方式皆可
func(1,2)
func(1,2,c=22)
# func(1,2,33)
#  *和**的魔术用法
"""
    在函数的定义处:* **相当于打包操作(一个是元组,一个是字典)
    在函数的调用处:* **相当于解包操作(把里面的元素一个一个拿出来当成参数进行行数的调用)
"""
def func(a,b,c):
    print(a,b,c)
lst=[1,2,3]
func(*lst)  #相当于func(1,2,3)把列表表妹的每个元素都单独拿出来当成参数就那些参数的调用

def func(a,b,c,d):
    print(a)
    print(b,c,d)
dictvar={"b":"2","c":"3","d":"4"}
func(1,**dictvar)    #相当于func(1,b=2,c=3,d=4)把字典里面的每个键值对,都拿出来,变成键=值的兴衰,进行关键字实参赋值操作

#扩展
#函数的定义处
def func(a,b,*,c,d):
    print(a,b)
    print(c,d)
lst=[1,2]
dictvar={"c":3,"d":4}
#函数的调用处
func(*lst,**dictvar)

"""
在字典的前面加上一个*,默认只传递键,
一个*号可以跟list tuple set,常用的一般是list
二个**后面可以跟dict,把键值对变成键=值的形式进行函数调用
"""
def func(a,b):
    print(a,b)
dictvar={"c":3,"d":4}
func(*"pa")

"""
函数的定义处:参数的定义有顺序:
普通形参-->默认形参-->普通收集参数-->命名关键字参数-->关键字收集参数
def func(*args,**kwargs):这样的形式定义函数,可以收到所有种类的参数
"""
4.函数的返回值
"""
return自定义返回值,如果没有写return,默认返回None
功能:把值返回到函数的调用处;
(1)return后面可以返回值 是自定义的,除了6大标准数据类型之外,还有类,对象,函数
(2)如果执行了return语句,意味着函数终止,后面的代码不执行
"""
def func():
    #return 1
    # return 3.14
    # return 4+4j
    # return True
    # return [1,2,3]
    # return {"a":1,"b":2}
    pass
res=func()
print(res)
res=print(1)
print(res)
print("------------")
#(2)如果执行了return语句,意味着函数终止,后面的代码不执行
def func():
    print("这句话执行了1")
    print("这句话执行了2")
    return 1
    print("这句话执行了3")
    print("这句话执行了4")
res=func()
print(res)
print("------------")
def func():
    for i in range(5):
        if i==3:
            return i
        print(i)
res=func()
#(3)计算器小例子
def calc(sign,num1,num2):
    if sign=="+":
        res=num1+num2
    elif sign=="-":
        res = num1 - num2
    elif sign == "*":
        res = num1 * num2
    elif sign == "/":
        if num2==0:
            return "除数不能为0"
        res = num1 / num2
    return res
    # print(sign,num1,num2)
res=calc("+",1,2)
res=calc("-",-1,90)
res=calc("*",10,52)
res=calc("/",52,10)
res=calc("/",52,0)
print(res)
5.函数名的函数
###函数名的函数
# 1.函数名是个特殊的变量,可以当做变量赋值
def func():
    print("函数名可以当做变量使用")
abc=45
abc=func
print(abc)
abc()
# 2.函数名可以作为容器类型数据的元素
def func1():
    print(1)
def func2():
    print(2)
def func3():
    print(3)
lst=[func1,func2,func3]
for i in lst:
    i()  #func1()   func2()   func3()

# 3.函数名可以作为函数的参数
def func1(func):
    func()
def func2():
    print("我是 func2")
#func形参接收到了func2这个实参函数,调用func1执行里面的代码块
func1(func2)
# 4.函数名可以作为函数的返回值
def func3(func):
    return func
def func4():
    print("我是 func4")
#func4 这个实参被func接收到,执行func3代码块内容,直接return func4,res接收到了返回值func4
res=func3(func4)
res()  #func4()
#__doc__或者help查看文档
# help(print)
res=print.__doc__
print(res)

#如何自定义函数的文档
def eat_big_chang(something):
    """
    功能:模拟吃大肠
    :param 大肠
    :return: 吃没 吃完的状态
    """
    print("我是在模拟{}过程".format(something))
    print("第一步,找肠子头")
    print("第二步,把肠子放在嘴里")
    print("第三步,使劲唆")
    return "擦擦嘴,非常满足,吃完了"
eat_big_chang("吃大肠")
#方法1:用函数__doc__
res=eat_big_chang.__doc__
print(res)
#方法2
help(eat_big_chang)
6.全局变量与局部变量
"""
局部变量:定义在函数内部的变量
全局变量:定义在函数外部或者用global关键字在函数内部定义的变量
作用域:作用的范围
局部变量的作用域:只限定在函数内部
全局变量的作用域:横跨整个文件
"""
#(1).局部边的获取与修改
def func():
    a=15
    #获取局部变量
    print(a)
    #修改局部变量
    a=17
    print(a)
func()
# print(a)  a 未被定义

#(2)全部变量的获取与修改
b=100
#获取全局变量
print(b)
b+=200
print(b)
#(3)在函数内部可以直接获取全局变量,但不能直接修改
# 用global关键字,修改全局变量
c=50
def func():
    global c
    print(c)
    c = 60
    print(c)

func()
print(c)
#(4)在函数内部可以直接定义一个全局变量
def func():
    global d
    d=90
func()
print(d)
#z总结
"""
global关键字:如果函数外部没有该变量,就是在函数内部定义一个全局变量
global关键字:如果函数外部有该变量,就是在函数内修改一个全局变量
global用来修饰全局变量,有就修改,没有就创建
"""
7.函数的嵌套
"""
函数之间允许嵌套:
嵌套在外层的就是外函数
嵌套在内层的就是内函数
"""
def outer():
    def inner():
        print("111")
    inner()
"""
(1)内部函数可以直接在函数外部调用吗?   --->不行
(2)调用外部函数后,内部函数可以在函数外部调用吗?     --->不行
(3)内部函数可以在函数内部调用吗?    --->行
(4)内部函数在函数内部调用时,是否有先后顺序?  在定义后在调用  
注:Python没有预加载机制,不能提前把函数加载到内存当中
"""
outer()
# inner()
#外层是outer函数,里面有inner,中间有smaller,如果调用smaller
def outer():
    def inner():
        a=90
        def smaller():
            print(a)
            print(id)
            print("我是smaller")
        smaller()
    inner()
outer()

#LEGB原则(就近找变量原则)
"""
#找寻变量的调用顺序,采用LEGB原则(即就近原则)
B--Builtin(python):python内置模块的命名空间   (内建作用域)
G--global(module):函数外部所在的命名空间   (全局作用域)
E--enclosing function locals:外部嵌套函数的作用域  (嵌套作用域)
L--local(function):当前嵌套函数的作用域     (局部作用域)
依据就近原则,从上往下  从里往外  依次寻找
"""

#生命周期
"""
内置命名空间中的所有变量-->全局命名空间中的所有变量-->局部命名空间中的所有变量
"""
#命名空间:划分一块区域保存所有数据,以字典的方式存储(变量与值形成映射关系),一共三种
#(1)内建命名空间:解释器启动时创建,直到解释器运行结束,生存周期最长
#(2)全局命名空间:文件运行时创建,直到解释器运行结束,生存周期较长
#(3)局部命名空间:函数调用时,里面的局部变量才创建,调用结束后即释放,生存周期较短

#命名空间的提出是为了划分和控制变量是否可见,以及生存周期的长度

#命名空间  创建顺序(了解):
# Python解释器启动-->创建内建命名空间-->创建全局命名空间-->创建局部命名空间
#命名空间  销毁顺序(了解):
# 函数调用结束后-->销毁函数对应的局部命名空间-->销毁全局命名空间数据-->小胡内建命名空间数据
8.nonlocal 用来修饰局部变量
"""
nonlocal 符合LEGB原则,就近原则找变量
(1)只能用来修饰局部变量
(2)nonlocal会不停的寻找上一层空间对应的值,拿来修改
(3)如果上一层找不到,继续往上找,再也找不到,直到报错
(4)不通过nonlocal,是否可以用来改变局部变量?-->可以,需要使用列表进行操作
"""
#(1)只能用来修饰局部变量
a=90
def func():
    a=80
    print(a)
func()
#(2)nonlocal会不停的寻找上一层空间对应的值,拿来修改
"""
通过LEGB原则,可以获取到上一层空间的值,只能单纯的获取,不能直接修改,如果需要修改,通过nonlocal加以修饰
"""
def outer():
    a=20
    def inner():
        nonlocal a   #定义a
        print(a)
        a+=1
        print(a)
    inner()
outer()

#(3)如果上一层找不到,继续往上找,再也找不到,直到报错
def outeer():
    def inner():
        a=100    #nonlocal只能修饰局部变量,不能为全局变量
        def smaller():
            nonlocal a
            a+=10
            print(a)
        smaller()
    inner()
outer()
#(4)不通过nonlocal,是否可以用来改变局部变量?-->可以,需要使用列表进行操作
def outer():
    lst=[100,101,102]
    def inner():
        lst[0]+=1
        inner()
    print(lst)
outer()
9.闭包函数
"""
概念:内函数使用了外函数的局部变量,
并且外函数把内函数返回出来的过程,叫做闭包
这个内函数叫做闭包函数
"""
def li_family():
    father="李嘉诚"
    def father_say():
        print("{}先定一个小目标,买一个英国伦敦!".format(father))
    return father_say
func=li_family()
print(func)
func()

#(2)闭包函数的升级
def liao_family():
    jiejie="马蓉"
    meimei="马若"
    money=1000
    def jiejie_hobby():
        nonlocal money
        money-=500
        print("买名牌包包,名牌手表,名牌狗链。。。。家里的钱还剩下%s"%(money))
    def meimei_hobby():
        nonlocal money
        money-=400
        print("n宁愿在宝马里面哭,也不愿在自行车上面撒欢,家里的钱,还剩下%s"%(money))
    def big_guanjia():
        return jiejie_hobby,meimei_hobby    #返回一个元组
        # return [jiejie_hobby,meimei_hobby]
    return big_guanjia
func=liao_family()
print(func)
tup=func()
print(tup)   #(<function liao_family.<locals>.jiejie_hobby at 0x0000000001E5D0D0>, <function liao_family.<locals>.meimei_hobby at 0x0000000001E5D158>)
jiejie=tup[0]()
meimei=tup[1]()
10.闭包函数的意义
###闭包函数的特点
"""
内函数使用了外函数的局部变量,外函数的局部变量与内函数的发生绑定,延长了该变量的生命周期
"""
def outer(val):
    def inner(num):
        return num+val
    return inner
func=outer(10)
res=func(5)  #func=inner()=num+val=10+5=15
print(res)
"""
func=outer(10)
val 接收到这个值 return inner
因为内函数使用额外函数的局部变量val,val与内函数发生版本,延长该变量的生命周期,不释放

res=func()
num 接受到5这个值 return num+val return 5+10  ==>return 15
"""

#闭包函数的意义
"""
内函数使用了外函数的局部变量,并对闭包中的值起到了封装保护的作用,外部无法访问
模拟一个鼠标点击计数功能
"""
clicknum=0
def clickfunc():
    global clicknum
    clicknum+=1
    print(clicknum)
#模拟点击操作,点击一次就调用一次
clickfunc()
clickfunc()
clickfunc()
clickfunc()
clicknum=100
clickfunc()
print("------------------")
#用闭包函数来进行改造
def clickfunc():
    x=0
    def func():
        nonlocal x
        x+=1
        print(x)
    return func
clickfunc2=clickfunc()
clickfunc2()
clickfunc2()
clickfunc2()
clickfunc2()
clickfunc2()
11.locals 和 globals
"""
locals()获取当前作用域的所有变量
(1)如果locals在函数外:所获取的locals(),打印返回值之前的所有内容;如:函数之外的例子1
(2)如果locals在函数内:所获取的locals(),调用之前所有内容,如:函数内例子2-->func
"""
#(1)当前作用域的全局范围
# a=1
# b=2
# res=locals()
# c=3
# print(res)
#(2)当前作用域的全局范围
"""
zz=90
def func():
    d=4
    f=5
    res=locals()
    g=6
    print(res)
func()
"""
"""
globals 无论在函数内外,都只获取全局作用域当中的所有内容
(1)如果locals在函数外,所获取的globals(),打印返回值之前的所有内容
(2)如果locals在函数外,所获取的globals(),调用之前的所有内容
"""
#(1)当前作用域在全局范围
# a=1
# b=2
# res=globals()
# c=3
# print(res)
#(2)当前作用域在全局范围
"""
aa=11
bb=22
def func():
    d=1
    f=2
    res=globals()
    z=3
    print(res)
cc=33
func()
dd=44
"""
#(3)globals()  d冬天的创建全局变量
"""
globals() 返回的是系统的字典,只需要在字典里面添加键值对,就可以创建全局变量
字典中的键,就是变量名
字典中的值,就是变量所指代的值
"""
dic=globals()
print(dic)
# dic["wangwen"]="风流倜傥,玉树临风,美若天仙,才华横溢"
wangwen="风流倜傥,玉树临风,美若天仙,才华横溢"
print(wangwen)

#globals  批量创建全局变量
#创建p1-p5 5个全局变量
def func():
    dic=globals()
    for i in range(1,6):
        #p1-p5  5个键
        dic["p%d"%i]=i
func()
print(p1)
print(p2)
print(p3)
print(p4)
print(p5)
print(globals())
12.匿名函数:lambda
###匿名函数  =>  lambda表达式
"""
lambda 表达式:用一句话来表达只有返回值的函数
好处:
    简洁,方便,定义函数快速简单
语法:
    lambda 参数 : 返回值
"""
#(1)无参的lambda表达式
def func():
    return 123456
func=lambda :123456
res=func()
print(res)
#(2)有参的lambda表达式
def func(n):
    return type(n)
res=func("1234")
print(res)

func=lambda n:type(n)
res=func([1,2,3])
print(res)

#(3)带有条件判断的lambda表达式
def func():
    if n%2==0:
        return "偶数"
    else:
        return "奇数"
#三目运算符
"""
语法:真值 if条件表达式else假值
    如果条件表达式成立,执行真值
    如果条件表达式不成立,执行假值   
"""
n=11
res='偶数'if n%2==0 else "奇数"
print(res)
print("-----------")
n=90
func=lambda n:"偶数" if n%2==0 else "奇数"
print(func(n))
#计算参数中的最大值
def func(m,n):
    if m>n:
        return m
    else:
        return n
print(func(3,5))

func=lambda m,n: m if m>n else n
print(func(70,10))
13.递归函数
"""
递归函数:自己调用自己的函数
递:去
归:回
一去一回是递归
递归的最大深处:官网1000层
"""
#简单递归
def digui(n):
    print(n,"====11====")
    if n>0:
        digui(n-1)
    print(n,"====22====")
digui(5)

"""
去的过程
print(5,"====11====")
5>0 digui(5-1) digui(4)

print(4,"====11====")
4>0 digui(4-1) digui(3)

print(3,"====11====")
3>0 digui(3-1) digui(2)

print(2,"====11====")
2>0 digui(2-1) digui(1)

print(1,"====11====")
1>0 digui(1-1) digui(0)

print(0,"====11====")
0>0 条件不满足,往下执行
print(n,"====22====")


回的过程:巴生西没走完的代码继续执行
    回到上一次函数的调用处第17行,从第17行继续向下执行
    n=1  print(1,"====22====")

    回到上一次函数的调用处第17行,从第17行继续向下执行
    n=2  print(2,"====22====")

    回到上一次函数的调用处第17行,从第17行继续向下执行
    n=3  print(3,"====22====")

    回到上一次函数的调用处第17行,从第17行继续向下执行
    n=4  print(4,"====22====")

    回到上一次函数的调用处第17行,从第17行继续向下执行
    n=5  print(5,"====22====")

    函数彻底终止
"""

# def func():
#     func()            [Previous line repeated 995 more times]
# func()
"""
栈帧空间:为了运行函数所需开辟的空间
(1)每调用一次函数,就是开辟一个栈帧空间的过程
每结束一次函数,就是释放一个栈帧空间的过程
递归函数就是不停的开辟栈帧空间和释放栈帧空间的过程
(2)回的过程有2种触发时机:
    (1)当最后一层函数全部执行完毕,触发回的过程,回到上一层函数调用的地方
    (2)当遇到return返回值的时候,触发回的过程,回到上一层函数调用的地方
(3)如果递归层数过大,不推荐使用递归,如果使用,多添加一个跳出来的条件,防止内存溢出
"""
"""
栈帧空间彼此的数据是隔离的,彼此独立,各是各的空间
def abc(n):
    print(n) 
abc(1)
abc(2)
"""
#计算N的阶乘  5!=5*4*3*2*1
def jiecheg(n):
    if n<=1:
        return 1
    return n*jiecheg(n-1)
print(jiecheg(5))

"""
需要先把表达式的值算完之后再返回
n=5 return 5*jiecheng(5-1) =>5*jiecheng(4)
n=4 return 4*jiecheng(4-1) =>5*jiecheng(3)
n=3 return 3*jiecheng(3-1) =>5*jiecheng(2)
n=2 return 2*jiecheng(2-1) =>5*jiecheng(1)
n=1 n<=1  满足return1
回的过程
n=2 return 2*jiecheng(2-1) =>2*jiecheng(1)   =>2*1
n=3 return 3*jiecheng(3-1) =>3*jiecheng(2)   =>3*2*1
n=4 return 4*jiecheng(4-1) =>4*jiecheng(3)   =>4*3*2*1
n=5 return 5*jiecheng(5-1) =>5*jiecheng(4)   =>5*4*3*2*1
最后直接 return  5*4*3*2*1=120
"""